Merge branch 'master' into nsurl-additions

This commit is contained in:
rfm 2020-11-06 09:36:42 +00:00 committed by GitHub
commit 17af685b1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1152 additions and 111 deletions

77
.clang-format Normal file
View file

@ -0,0 +1,77 @@
# Copyright (C) 2015 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Modified from gcc's clang-format config.
# clang-format 7.0.1 is required
#
# To utilize the tool to lines just touched by a patch, use
# clang-format-diff script that is usually also packaged with clang-format.
#
# Example of usage:
# git diff -U0 --no-color | clang-format-diff -p1
# (here the tool will generate a patch)
# git diff -U0 --no-color | clang-format-diff -p1 -i
# (modifications are applied)
---
AccessModifierOffset: -2
AlwaysBreakAfterReturnType: TopLevel
AlignConsecutiveDeclarations: true
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
# Newer clang-format has BS_GNU
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: true
SplitEmptyFunction: false
BreakBeforeTernaryOperators: true
ColumnLimit: 80
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
ForEachMacros: []
IndentCaseLabels: false
NamespaceIndentation: None
PenaltyBreakBeforeFirstCallParameter: 100
DerivePointerAlignment: false
PointerAlignment: Right
SortIncludes: false
SpaceAfterCStyleCast: true
SpaceBeforeParens: ControlStatements
SpacesBeforeTrailingComments: 1
UseTab: Always
AlignEscapedNewlines: Right
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: All
AlwaysBreakTemplateDeclarations: MultiLine
KeepEmptyLinesAtTheStartOfBlocks: false
# TODO
# MacroBlockBegin:
# MacroBlockEnd:

View file

@ -108,6 +108,7 @@ before_script: |
windows)
DEP_ROOT=/c/staging
setx -m PATH "C:\staging;%PATH%"
CONFIGURE_OPTS=--without-unwind
;;
esac
export LIBRARY_PATH=$DEP_ROOT/lib:$DEP_ROOT/lib64:$LIBRARY_PATH
@ -124,7 +125,7 @@ before_script: |
. $GNUSTEP_MAKEFILES/GNUstep.sh
script:
# configure and make need to be executed via MinGW shell on Windows ($mingw is undefined on Linux)
- $mingw ./configure $BASE_ABI || (cat config.log && false)
- $mingw ./configure $BASE_ABI $CONFIGURE_OPTS || (cat config.log && false)
- $mingw make && $mingw make install && $mingw make check || (cat Tests/tests.log && false)
# set up packages cache (currently used on Windows only)

View file

@ -1,4 +1,4 @@
2020-08-03 Frederik Seiffert <frederik@algoriddim.com>
2020-10-06-03 Frederik Seiffert <frederik@algoriddim.com>
* Headers/Foundation/NSURL.h,
* Source/NSURL.h: Add NSURL methods:
@ -7,6 +7,10 @@
- fileReferenceURL
- filePathURL
2020-08-30 Fred Kiefer <fredkiefer@gmx.de>
* Source/NSDateComponentsFormatter.m: Fix use of wrong operator.
2020-08-02 Gregory John Casamento <greg.casamento@gmail.com>
* Headers/Foundation/NSNotification.h: Add NSNotificatioName typedef

View file

@ -93,7 +93,7 @@ typedef NSInteger NSOperationQueuePriority;
/** Returns all the dependencies of the receiver in the order in which they
* were added.
*/
- (NSArray *)dependencies;
- (NSArray *) dependencies;
/** This method should return YES if the -cancel method has been called.<br />
* NB. a cancelled operation may still be executing.
@ -208,8 +208,8 @@ typedef NSInteger NSOperationQueuePriority;
}
// Managing the blocks in the Operation
+ (instancetype)blockOperationWithBlock: (GSBlockOperationBlock)block;
- (void)addExecutionBlock: (GSBlockOperationBlock)block;
+ (instancetype) blockOperationWithBlock: (GSBlockOperationBlock)block;
- (void) addExecutionBlock: (GSBlockOperationBlock)block;
- (NSArray *) executionBlocks;
@end

View file

@ -34,12 +34,15 @@ extern "C" {
@class NSTimer, NSDate, NSPort;
typedef NSString* NSRunLoopMode;
/**
* Run loop mode used to deal with input sources other than NSConnections or
* dialog windows. Most commonly used. Defined in
* <code>Foundation/NSRunLoop.h</code>.
*/
GS_EXPORT NSString * const NSDefaultRunLoopMode;
GS_EXPORT NSRunLoopMode const NSDefaultRunLoopMode;
GS_EXPORT NSRunLoopMode const NSRunLoopCommonModes;
@interface NSRunLoop : NSObject
{

View file

@ -29,6 +29,7 @@
#if OS_API_VERSION(MAC_OS_X_VERSION_10_2,GS_API_LATEST) && GS_API_VERSION( 11300,GS_API_LATEST)
#import <Foundation/NSObject.h>
#import <Foundation/NSRunLoop.h>
#if defined(__cplusplus)
extern "C" {
@ -66,11 +67,27 @@ extern "C" {
+ (NSURLConnection *) connectionWithRequest: (NSURLRequest *)request
delegate: (id)delegate;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
/**
* Start the asynchronous load. This method is only needed if NO is passed
* into startImmediately when calling initWithRequest: delegate: startImmediately.
*/
- (void) start;
#endif
/**
* Cancel the asynchronous load in progress (if any) for this connection.
*/
- (void) cancel;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop
forMode: (NSRunLoopMode)mode;
- (void) unscheduleFromRunLoop: (NSRunLoop *)aRunLoop
forMode: (NSRunLoopMode)mode;
#endif
/** <init />
* Initialises the receiver with the specified request (performing
* a deep copy so that the request does not change during loading)
@ -86,6 +103,24 @@ extern "C" {
*/
- (id) initWithRequest: (NSURLRequest *)request delegate: (id)delegate;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
/** <init />
* Initialises the receiver with the specified request (performing
* a deep copy so that the request does not change during loading)
* and delegate.<br />
* This automatically initiates an asynchronous load for the request
* if and only if startImmediately is set to YES.<br />
* Processing of the request is done in the thread which calls this
* method, so the thread must run its current run loop
* (in NSDefaultRunLoopMode) for processing to continue/complete.<br />
* The delegate will receive callbacks informing it of the progress
* of the load.<br />
* This method breaks with convention and retains the delegate object,
* releasing it when the connection finished loading, fails, or is cancelled.
*/
- (id) initWithRequest: (NSURLRequest *)request delegate: (id)delegate startImmediately: (BOOL)startImmediately;
#endif
@end

View file

@ -90,11 +90,11 @@
#define IF_NO_GC(X)
#ifndef ENTER_POOL
#define ENTER_POOL @autoreleasepool{do{
#define ENTER_POOL @autoreleasepool{
#endif
#ifndef LEAVE_POOL
#define LEAVE_POOL }while(0);}
#define LEAVE_POOL }
#endif
#ifndef DEALLOC
@ -216,22 +216,23 @@ id __object = (object); (__object != nil) ? [__object autorelease] : nil; })
#ifndef ENTER_POOL
/**
* ENTER_POOL creates an autorelease pool and places subsequent code
* in a do/while loop (executed only once) which can be broken out of
* to reach the point when the pool is drained.<br />
* in a block.<br />
* The block must be terminated with a corresponding LEAVE_POOL.<br />
* You should not return from such a block of code (to do so could
* leak an autorelease pool and give objects a longer lifetime than
* they ought to have. If you wish to leave the block of code early,
* you may do so using a 'break' statement.
* You should not break, continue, or return from such a block of code
* (to do so could leak an autorelease pool and give objects a longer
* lifetime than they ought to have. If you wish to leave the block of
* code early, you should ensure that doing so causes the autorelease
* pool outside the block to be released promptly (since that will
* implicitly release the pool created at the start of the block too).
*/
#define ENTER_POOL {NSAutoreleasePool *_lARP=[NSAutoreleasePool new];do{
#define ENTER_POOL {NSAutoreleasePool *_lARP=[NSAutoreleasePool new];
#endif
#ifndef LEAVE_POOL
/**
* LEAVE_POOL terminates a block of code started with ENTER_POOL.
*/
#define LEAVE_POOL }while(0);[_lARP drain];}
#define LEAVE_POOL [_lARP drain];}
#endif
#ifndef DEALLOC
@ -244,14 +245,16 @@ id __object = (object); (__object != nil) ? [__object autorelease] : nil; })
#endif
#ifndef CREATE_AUTORELEASE_POOL
/** DEPRECATED ... use ENTER_POOL and LEAVE_POOL
/** DEPRECATED ... use ENTER_POOL and LEAVE_POOL and make sure your
* code does not break/continue/return out of the section of code.
*/
#define CREATE_AUTORELEASE_POOL(X) \
NSAutoreleasePool *X = [NSAutoreleasePool new]
#endif
#ifndef RECREATE_AUTORELEASE_POOL
/** DEPRECATED ... use ENTER_POOL and LEAVE_POOL
/** DEPRECATED ... use ENTER_POOL and LEAVE_POOL and make sure your
* code does not break/continue/return out of the section of code.
*/
#define RECREATE_AUTORELEASE_POOL(X) \
DESTROY(X);\

View file

@ -61,6 +61,7 @@
{
@public
GSIMapTable_t map;
NSUInteger _version;
}
@end
@ -349,6 +350,15 @@ static SEL objSel;
return nil;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__unsafe_unretained id[])stackbuf
count: (NSUInteger)len
{
state->mutationsPtr = (unsigned long *)self;
return GSIMapCountByEnumeratingWithStateObjectsCount
(&map, state, stackbuf, len);
}
@end
@implementation _GSMutableInsensitiveDictionary
@ -396,6 +406,7 @@ static SEL objSel;
{
GSIMapNode node;
_version++;
if (aKey == nil)
{
NSException *e;
@ -425,11 +436,14 @@ static SEL objSel;
{
GSIMapAddPair(&map, (GSIMapKey)aKey, (GSIMapVal)anObject);
}
_version++;
}
- (void) removeAllObjects
{
_version++;
GSIMapCleanMap(&map);
_version++;
}
- (void) removeObjectForKey: (id)aKey
@ -439,7 +453,18 @@ static SEL objSel;
NSWarnMLog(@"attempt to remove nil key from dictionary %@", self);
return;
}
_version++;
GSIMapRemoveKey(&map, (GSIMapKey)aKey);
_version++;
}
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__unsafe_unretained id[])stackbuf
count: (NSUInteger)len
{
state->mutationsPtr = (unsigned long *)&_version;
return GSIMapCountByEnumeratingWithStateObjectsCount
(&map, state, stackbuf, len);
}
@end

View file

@ -5724,14 +5724,20 @@ appendString(NSMutableData *m, NSUInteger offset, NSUInteger fold,
return nil;
}
/**
* Convenience method to fetch the content file name from the header.
/** Convenience method to fetch the content file name from the content-type
* or content-disposition header.
*/
- (NSString*) contentFile
{
GSMimeHeader *hdr = [self headerNamed: @"content-disposition"];
GSMimeHeader *hdr = [self headerNamed: CteContentType];
NSString *str = [hdr parameterForKey: @"name"];
return [hdr parameterForKey: @"filename"];
if (nil == str)
{
hdr = [self headerNamed: @"content-disposition"];
str = [hdr parameterForKey: @"filename"];
}
return str;
}
/**

View file

@ -52,6 +52,7 @@
#ifdef HAVE_LIBXML
#import "GNUstepBase/GSObjCRuntime.h"
#import "GNUstepBase/NSDebug+GNUstepBase.h"
#import "GNUstepBase/NSObject+GNUstepBase.h"
#import "GNUstepBase/GSMime.h"
#import "GNUstepBase/GSXML.h"
@ -997,7 +998,10 @@ static NSMapTable *nodeNames = 0;
1,
1,
"utf-8");
xmlOutputBufferFlush(buf);
if (xmlOutputBufferFlush(buf) < 0)
{
NSDebugMLog(@"Failed to flush XML description");
}
#if LIBXML_VERSION < 20900
string = UTF8StrLen(buf->buffer->content, buf->buffer->use);
#else

View file

@ -332,7 +332,7 @@ randombytes(uint8_t *buf, unsigned len)
}
stream.next_out = dst + stream.total_out;
stream.avail_out = (unsigned)(capacity - stream.total_out);
deflate(&stream, Z_FINISH);
(void)deflate(&stream, Z_FINISH);
}
deflateEnd(&stream);
result = [NSMutableData alloc];

View file

@ -426,7 +426,6 @@ static SEL objSel;
{
GSIMapNode node;
_version++;
if (aKey == nil)
{
NSException *e;
@ -448,6 +447,7 @@ static SEL objSel;
userInfo: self];
[e raise];
}
_version++;
node = GSIMapNodeForKey(&map, (GSIMapKey)aKey);
if (node)
{

View file

@ -100,7 +100,7 @@
{
NSString *result = @"";
if (_allowedUnits | NSCalendarUnitYear)
if (_allowedUnits & NSCalendarUnitYear)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -115,7 +115,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -142,7 +142,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitMonth)
if (_allowedUnits & NSCalendarUnitMonth)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -157,7 +157,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -184,7 +184,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitDay)
if (_allowedUnits & NSCalendarUnitDay)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -199,7 +199,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -226,7 +226,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitHour)
if (_allowedUnits & NSCalendarUnitHour)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -241,7 +241,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -268,7 +268,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitMinute)
if (_allowedUnits & NSCalendarUnitMinute)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -283,7 +283,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -310,7 +310,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitSecond)
if (_allowedUnits & NSCalendarUnitSecond)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -325,7 +325,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
NSString *s;
@ -352,7 +352,7 @@
}
}
}
if (_allowedUnits | NSCalendarUnitWeekOfMonth)
if (_allowedUnits & NSCalendarUnitWeekOfMonth)
{
if (_unitsStyle == NSDateComponentsFormatterUnitsStyleSpellOut)
{
@ -369,7 +369,7 @@
else
{
if (_zeroFormattingBehavior
| NSDateComponentsFormatterZeroFormattingBehaviorDefault)
& NSDateComponentsFormatterZeroFormattingBehaviorDefault)
{
long wom = (long)[components weekOfMonth];
NSString *s = [NSString stringWithFormat: @"%2ld", wom];
@ -437,13 +437,13 @@
- (void) setAllowedUnits: (NSCalendarUnit)units
{
if (units | NSCalendarUnitYear
&& units | NSCalendarUnitMonth
&& units | NSCalendarUnitDay
&& units | NSCalendarUnitHour
&& units | NSCalendarUnitMinute
&& units | NSCalendarUnitSecond
&& units | NSCalendarUnitWeekOfMonth)
if (units & NSCalendarUnitYear
&& units & NSCalendarUnitMonth
&& units & NSCalendarUnitDay
&& units & NSCalendarUnitHour
&& units & NSCalendarUnitMinute
&& units & NSCalendarUnitSecond
&& units & NSCalendarUnitWeekOfMonth)
{
[NSException raise: NSInvalidArgumentException
format: @"Passed invalid unit into allowedUnits"];

View file

@ -369,8 +369,8 @@ _GSDebugAllocationAdd(Class c, id o)
{
bytes = the_table[num_classes].nominal_size;
}
the_table[num_classes].bytes += bytes;
the_table[num_classes].totalb += bytes;
the_table[num_classes].bytes = bytes;
the_table[num_classes].totalb = bytes;
the_table[num_classes].lastb = 0;
the_table[num_classes].lastc = 0;
the_table[num_classes].totalc = 1;

View file

@ -2813,7 +2813,8 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
if (dirname)
{
// Skip it if it is hidden and flag is yes...
if ([[dir.path lastPathComponent] hasPrefix: @"."] && _flags.skipHidden == YES)
if ([[dir.path lastPathComponent] hasPrefix: @"."]
&& _flags.skipHidden == YES)
{
continue;
}
@ -2843,14 +2844,14 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
stringWithFileSystemRepresentation: dirname
length: strlen(dirname)];
#endif
/* if we have a null FileName something went wrong (charset?) and we skip it */
/* if we have a null FileName something went wrong (charset?)
* and we skip it */
if (returnFileName == nil)
continue;
returnFileName = RETAIN([dir.path stringByAppendingPathComponent:
returnFileName]);
/* TODO - can this one can be removed ? */
if (!_flags.justContents)
_currentFilePath = RETAIN([_topPath stringByAppendingPathComponent:
returnFileName]);
@ -2904,13 +2905,16 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
else
{
BOOL flag = YES;
NSDebugLog(@"Failed to recurse into directory '%@' - %@",
_currentFilePath, [NSError _last]);
if(_errorHandler != NULL)
if (_errorHandler != NULL)
{
flag = CALL_BLOCK(_errorHandler, [NSURL URLWithString: _currentFilePath], [NSError _last]);
flag = CALL_BLOCK(_errorHandler,
[NSURL URLWithString: _currentFilePath],
[NSError _last]);
}
if(flag == NO)
if (flag == NO)
{
return nil; // Stop enumeration...
}

View file

@ -41,22 +41,24 @@
if (((self = [super init])) != nil)
{
[inv retainArguments];
_invocation = [inv retain];
_invocation = RETAIN(inv);
}
return self;
}
- (id) initWithTarget: (id)target selector: (SEL)aSelector object: (id)arg
{
NSMethodSignature *methodSignature;
NSInvocation *inv;
NSMethodSignature *methodSignature;
NSInvocation *inv;
methodSignature = [target methodSignatureForSelector: aSelector];
inv = [NSInvocation invocationWithMethodSignature: methodSignature];
[inv setTarget: target];
[inv setSelector: aSelector];
if ([methodSignature numberOfArguments] > 2)
[inv setArgument: &arg atIndex: 2];
{
[inv setArgument: &arg atIndex: 2];
}
return [self initWithInvocation: inv];
}
@ -65,16 +67,20 @@
if (![self isCancelled])
{
NS_DURING
[_invocation invoke];
{
[_invocation invoke];
}
NS_HANDLER
_exception = [localException copy];
{
ASSIGN(_exception, localException);
}
NS_ENDHANDLER
}
}
- (NSInvocation *) invocation
{
return [[_invocation retain] autorelease];
return AUTORELEASE(RETAIN(_invocation));
}
- (id) result
@ -123,8 +129,8 @@
- (void) dealloc
{
[_invocation release];
[_exception release];
DESTROY(_invocation);
DESTROY(_exception);
[super dealloc];
}

View file

@ -1200,7 +1200,22 @@ static NSNotificationCenter *default_center = nil;
}
NS_HANDLER
{
NSLog(@"Problem posting notification: %@", localException);
BOOL logged;
/* Try to report the notification along with the exception,
* but if there's a problem with the notification itself,
* we just log the exception.
*/
NS_DURING
NSLog(@"Problem posting %@: %@", notification, localException);
logged = YES;
NS_HANDLER
logged = NO;
NS_ENDHANDLER
if (NO == logged)
{
NSLog(@"Problem posting notification: %@", localException);
}
}
NS_ENDHANDLER
}

View file

@ -85,7 +85,7 @@
/* platforms which do not support weak */
#if (__GNUC__ == 3) && defined (__WIN32)
#if defined (__WIN32)
#define WEAK_ATTRIBUTE
#undef SUPPORT_WEAK
#else

View file

@ -503,12 +503,11 @@ static NSArray *empty = nil;
@end
@implementation NSOperation (Private)
/* NB code calling this method must ensure that the receiver is retained
* until after the method returns.
*/
- (void) _finish
{
/* retain while finishing so that we don't get deallocated when our
* queue removes and releases us.
*/
RETAIN(self);
[internal->lock lock];
if (NO == internal->finished)
{
@ -533,12 +532,11 @@ static NSArray *empty = nil;
}
}
[internal->lock unlock];
RELEASE(self);
}
@end
@implementation NSBlockOperation
+ (instancetype) blockOperationWithBlock: (GSBlockOperationBlock)block
@ -983,12 +981,17 @@ static NSOperationQueue *mainQueue = nil;
- (void) _thread
{
ENTER_POOL
CREATE_AUTORELEASE_POOL(arp);
[[[NSThread currentThread] threadDictionary] setObject: self
forKey: threadKey];
for (;;)
{
/* We use a pool for each operation in case releasing the operation
* causes it to be deallocated, and the deallocation of the operation
* autoreleases something which needs to be cleaned up.
*/
RECREATE_AUTORELEASE_POOL(arp);
NSOperation *op;
NSDate *when;
BOOL found;
@ -1046,7 +1049,7 @@ static NSOperationQueue *mainQueue = nil;
[internal->lock lock];
internal->threadCount--;
[internal->lock unlock];
LEAVE_POOL
DESTROY(arp);
[NSThread exit];
}

View file

@ -129,6 +129,7 @@
{
case 1:
[pnc setNickname: [nameArray objectAtIndex: 0]];
break;
case 2:
[pnc setGivenName: [nameArray objectAtIndex: 0]];
[pnc setFamilyName: [nameArray objectAtIndex: 1]];

View file

@ -345,7 +345,7 @@ foundIgnorableWhitespace: (NSString *)string
}
else if ([elementName isEqualToString: @"real"])
{
ASSIGN(plist, [NSNumber numberWithDouble: [value doubleValue]]);
ASSIGN(plist, [NSNumber numberWithDouble: strtod([value cString], NULL)]);
}
else if ([elementName isEqualToString: @"true"])
{
@ -1135,7 +1135,7 @@ static id parsePlItem(pldata* pld)
else
{
result = [[NSNumber alloc]
initWithUnsignedLongLong: strtoull(buf, 0, 10)];
initWithUnsignedLongLong: strtoull(buf, NULL, 10)];
}
}
else if (type == 'B')
@ -1169,12 +1169,12 @@ static id parsePlItem(pldata* pld)
}
else if (type == 'R')
{
unichar buf[len];
double d = 0.0;
char buf[len+1];
for (i = 0; i < len; i++) buf[i] = ptr[i];
GSScanDouble(buf, len, &d);
result = [[NSNumber alloc] initWithDouble: d];
buf[len] = '\0';
result = [[NSNumber alloc]
initWithDouble: strtod(buf, NULL)];
}
else
{
@ -2481,6 +2481,18 @@ static BOOL classInitialized = NO;
return dest;
}
/**
* <p>Make <var>obj</var> into a plist in <var>str</var>, using the locale <var>loc</var>.</p>
*
* <p>If <var>*str</var> is <code>nil</code>, create a <ref>GSMutableString</ref>.
* Otherwise <var>*str</var> must be a GSMutableString.</p>
*
* <p>Options:</p><ul>
* <li><var>step</var> is the indent level.</li>
* <li><var>forDescription</var> enables OpenStep formatting.</li>
* <li><var>xml</var> enables XML formatting.</li>
* </ul>
*/
void
GSPropertyListMake(id obj, NSDictionary *loc, BOOL xml,
BOOL forDescription, unsigned step, id *str)
@ -2757,7 +2769,7 @@ GSPropertyListMake(id obj, NSDictionary *loc, BOOL xml,
// not the other way round,
NSData *data = [self dataWithPropertyList: aPropertyList
format: aFormat
options: 0
options: anOption
error: error];
return [stream write: [data bytes] maxLength: [data length]];

View file

@ -74,7 +74,8 @@
#endif
NSString * const NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
NSRunLoopMode const NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
NSRunLoopMode const NSRunLoopCommonModes = @"NSRunLoopCommonModes";
static NSDate *theFuture = nil;

View file

@ -1292,16 +1292,16 @@ quotedFromString(NSString *aString)
NULL, /* thread attrs */
1, /* inherit handles */
0
|CREATE_NO_WINDOW
/* One would have thought the the CREATE_NO_WINDOW flag should be used,
* but apparently this breaks for old 16bit applications/tools on XP.
* So maybe we want to leave it out?
/* We don't want a subtask to be run min a window since that would prevent
* startup of background tasks. If a subtask wants a window, it should
* create it itself.
*/
// |DETACHED_PROCESS
|CREATE_NO_WINDOW
/* We don't set the DETACHED_PROCESS flag as it actually means that the
* child task should get a new Console allocated ... and that means it
* will pop up a console window ... which looks really bad.
*/
// |DETACHED_PROCESS
|CREATE_UNICODE_ENVIRONMENT,
envp, /* env block */
(const unichar*)[[self currentDirectoryPath] fileSystemRepresentation],

View file

@ -157,6 +157,11 @@ typedef struct
return AUTORELEASE(o);
}
- (void) start
{
[this->_protocol startLoading];
}
- (void) cancel
{
[this->_protocol stopLoading];
@ -164,6 +169,25 @@ typedef struct
DESTROY(this->_delegate);
}
- (void) scheduleInRunLoop: (NSRunLoop *)aRunLoop
forMode: (NSRunLoopMode)mode
{
NSArray *modes = [NSArray arrayWithObject: mode];
[aRunLoop performSelector: @selector(start)
target: self
argument: nil
order: 0
modes: modes];
}
- (void) unscheduleFromRunLoop: (NSRunLoop *)aRunLoop
forMode: (NSRunLoopMode)mode
{
[aRunLoop cancelPerformSelector: @selector(start)
target: self
argument: nil];
}
- (void) dealloc
{
if (this != 0)
@ -185,7 +209,7 @@ typedef struct
}
}
- (id) initWithRequest: (NSURLRequest *)request delegate: (id)delegate
- (id) initWithRequest: (NSURLRequest *)request delegate: (id)delegate startImmediately: (BOOL)startImmediately
{
if ((self = [super init]) != nil)
{
@ -226,12 +250,22 @@ typedef struct
initWithRequest: this->_request
cachedResponse: nil
client: (id<NSURLProtocolClient>)self];
[this->_protocol startLoading];
if (startImmediately == YES)
{
[this->_protocol startLoading];
}
this->_debug = GSDebugSet(@"NSURLConnection");
}
return self;
}
- (id) initWithRequest: (NSURLRequest *)request delegate: (id)delegate
{
return [self initWithRequest: request
delegate: delegate
startImmediately: YES];
}
@end

View file

@ -258,6 +258,11 @@ int main()
"data/number/data are ok in serialized property-list");
#endif
NSArray *a = [NSArray array];
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
@"val", a, @"val2", @"key2", nil];
PASS_EQUAL([d objectForKey: a], @"val", "array as dictionary key works")
[arp release]; arp = nil;
return 0;
}

View file

@ -1078,28 +1078,30 @@ static NSString *mainFont = nil;
}
else if ([name isEqual: @"gsdoc"] == YES)
{
NSString *stylesheetURL = [prop objectForKey: @"stylesheeturl"];
base = [prop objectForKey: @"base"];
if (base == nil)
{
NSLog(@"No 'base' document name supplied in gsdoc element");
break;
}
nextFile = [prop objectForKey: @"next"];
nextFile = [nextFile stringByAppendingPathExtension: @"html"];
prevFile = [prop objectForKey: @"prev"];
prevFile = [prevFile stringByAppendingPathExtension: @"html"];
upFile = [prop objectForKey: @"up"];
upFile = [upFile stringByAppendingPathExtension: @"html"];
else
{
NSString *stylesheetURL = [prop objectForKey: @"stylesheeturl"];
// special formatting for table-of-contents frames; ultimately
// this should be moved to stylesheet
isContentsDoc = ((stylesheetURL != nil) &&
([stylesheetURL rangeOfString: @"gsdoc_contents"].length > 0)) ?
YES : NO;
nextFile = [prop objectForKey: @"next"];
nextFile = [nextFile stringByAppendingPathExtension: @"html"];
prevFile = [prop objectForKey: @"prev"];
prevFile = [prevFile stringByAppendingPathExtension: @"html"];
upFile = [prop objectForKey: @"up"];
upFile = [upFile stringByAppendingPathExtension: @"html"];
[self outputNodeList: children to: buf];
// special formatting for table-of-contents frames; ultimately
// this should be moved to stylesheet
isContentsDoc = ((stylesheetURL != nil) &&
([stylesheetURL rangeOfString: @"gsdoc_contents"].length > 0))
? YES : NO;
[self outputNodeList: children to: buf];
}
}
else if ([name isEqual: @"head"] == YES)
{

View file

@ -72,7 +72,7 @@ MAN8_PAGES = gdomap.8
ifeq ($(add),yes)
TOOL_NAME = autogsdoc cvtenc plmerge sfparse xmlparse
else
TOOL_NAME = autogsdoc cvtenc gdnc gspath defaults pl plmerge \
TOOL_NAME = autogsdoc cvtenc gdnc gspath defaults pl plmerge plutil \
plparse sfparse pldes plget plser pl2link xmlparse HTMLLinker
CTOOL_NAME = gdomap
@ -97,6 +97,7 @@ plget_OBJC_FILES = plget.m
plser_OBJC_FILES = plser.m
plmerge_OBJC_FILES = plmerge.m
plparse_OBJC_FILES = plparse.m
plutil_OBJC_FILES = NSPropertyList+PLUtil.m plutil.m
sfparse_OBJC_FILES = sfparse.m
pl2link_OBJC_FILES = pl2link.m
locale_alias_OBJC_FILES = locale_alias.m

View file

@ -0,0 +1,47 @@
/** Permit handling JSON as plists, and writing Objective-C literals.
Copyright (C) 2020 Free Software Foundation, Inc.
Written by: Mingye Wang
Created: feb 2020
This file is part of the GNUstep Objective-C Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA.
*/
#import "Foundation/NSPropertyList.h"
/** Extra types supported by plutil. */
enum _PLUExtentedFormats
{
NSPropertyListJSONFormat = NSPropertyListBinaryFormat_v1_0 + 100,
/** https://clang.llvm.org/docs/ObjectiveCLiterals.html */
NSPropertyListObjectiveCFormat,
/** https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html */
NSPropertyListSwiftFormat,
};
@interface NSPropertyListSerialization (PLUtilAdditions)
+ (NSData *)_pdataFromPropertyList:(id)aPropertyList
format:(NSPropertyListFormat)aFormat
errorDescription:(NSString **)anErrorString;
+ (id)_ppropertyListWithData:(NSData *)data
options:(NSPropertyListReadOptions)anOption
format:(NSPropertyListFormat *)aFormat
error:(out NSError **)error;
+ (void)load;
@end

View file

@ -0,0 +1,122 @@
/** Permit handling JSON as plists, and writing Objective-C literals.
Copyright (C) 2020 Free Software Foundation, Inc.
Written by: Mingye Wang
Created: feb 2020
This file is part of the GNUstep Objective-C Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA.
*/
#import "NSPropertyList+PLUtil.h"
#import "GNUstepBase/GSObjCRuntime.h"
#import "Foundation/NSData.h"
#import "Foundation/NSUserDefaults.h"
#import "Foundation/NSJSONSerialization.h"
static IMP originalRead = 0;
static IMP originalWrite = 0;
@implementation NSPropertyListSerialization (PLUtilAdditions)
+ (NSData *)_pdataFromPropertyList:(id)aPropertyList
format:(NSPropertyListFormat)aFormat
errorDescription:(NSString **)anErrorString
{
NSError * myError = nil;
NSData * dest;
NSDictionary *loc;
loc = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
switch (aFormat)
{
case NSPropertyListJSONFormat:
dest = [NSJSONSerialization
dataWithJSONObject:aPropertyList
options:loc != nil ? NSJSONWritingPrettyPrinted : 0
error:&myError];
if (myError != nil && anErrorString != NULL)
{
*anErrorString = [myError description];
}
return dest;
case NSPropertyListObjectiveCFormat:
case NSPropertyListSwiftFormat:
*anErrorString = @"Not implemented";
return nil;
default:
return (*originalWrite)(self, _cmd, aPropertyList, aFormat, anErrorString);
}
}
+ (id)_ppropertyListWithData:(NSData *)data
options:(NSPropertyListReadOptions)anOption
format:(NSPropertyListFormat *)aFormat
error:(out NSError **)error;
{
NSError * myError = nil;
NSPropertyListFormat format;
NSJSONReadingOptions jsonOptions = NSJSONReadingAllowFragments;
id prop = (*originalRead)(self, _cmd, data, anOption, &format, &myError);
if (prop == nil)
if (format == NSPropertyListOpenStepFormat
|| format == NSPropertyListGNUstepFormat)
// rescue as json when we know it is not anything else
{
switch (anOption)
{
case NSPropertyListMutableContainersAndLeaves:
jsonOptions |= NSJSONReadingMutableLeaves;
/* FALLTHROUGH */
case NSPropertyListMutableContainers:
jsonOptions |= NSJSONReadingMutableContainers;
}
format = NSPropertyListJSONFormat;
prop = [NSJSONSerialization JSONObjectWithData:data
options:jsonOptions
error:&myError];
}
if (error != NULL)
*error = myError;
if (*aFormat != NULL)
*aFormat = format;
return prop;
}
+ (void)load
{
Method replacementRead;
Method replacementWrite;
replacementRead
= class_getClassMethod(self, @selector
(_ppropertyListWithData:options:format:error:));
replacementWrite
= class_getClassMethod(self, @selector
(_pdataFromPropertyList:format:errorDescription:));
originalRead
= class_replaceMethod(object_getClass(self),
@selector(propertyListWithData:options:format:error:),
method_getImplementation(replacementRead),
method_getTypeEncoding(replacementRead));
originalWrite
= class_replaceMethod(object_getClass(self),
@selector(dataFromPropertyList:
format:errorDescription:),
method_getImplementation(replacementWrite),
method_getTypeEncoding(replacementWrite));
}
@end

View file

@ -1557,7 +1557,7 @@ load_iface(const char* from)
}
if (ptr != buf)
{
strcpy(buf, ptr);
memmove(buf, ptr, strlen(ptr) + 1);
}
/*
* Strip comments.
@ -1629,7 +1629,7 @@ load_iface(const char* from)
}
if (ptr != buf)
{
strcpy(buf, ptr);
memmove(buf, ptr, strlen(ptr) + 1);
}
/*
* Strip comments.
@ -3968,7 +3968,7 @@ int ptype, struct sockaddr_in *addr, unsigned short *p, uptr *v)
*/
ptr = b;
port = 0;
while (ptr < &b[len])
while (ptr < (b + len))
{
ptr += 2 + ptr[0];
port++;
@ -4968,7 +4968,7 @@ printf(
}
if (ptr != buf)
{
strcpy(buf, ptr);
memmove(buf, ptr, strlen(ptr) + 1);
}
/*
* Strip comments.

View file

@ -17,7 +17,7 @@ pl, pldes, plser, plmerge, plparse, pl2link \- property list tools
.nf
.BI "plget " "key" [ more keys ]
.nf
.BI "plser " "filename(s)"
.BI "plser [ " "-format" "fmt" " ] filename(s)"
.nf
.BI "plmerge [ " "destination-file" " ] [ " "input-file(s)" " ]"
.nf
@ -49,9 +49,9 @@ Reads a text representation of a dictionary in property list format as
standard input, extracts the string value held in that dictionary with
the specified key, and writes the result to standard output.
Multiple keys may be used to extract values from nested dictionaries.
.IP "\fBplser\fR \fIfilename(s)\fR" 4
.IP "\fBplser\fR [ \fI-format format\fR ] \fIfilename(s)\fR" 4
Converts a text representation of a property list to a binary serialized
representation.
representation, or to another selected format.
.IP "\fBplmerge\fR [ \fIdestination-file\fR ] [ \fIinput-file(s)\fR ]" 4
Merges text property lists into a single property list
.IP "\fBplparse\fR \fIfilename(s)\fR" 4

630
Tools/plutil.m Normal file
View file

@ -0,0 +1,630 @@
/** Property list utility.
Copyright (C) 2020 Free Software Foundation, Inc.
Written by: Mingye Wang
Created: feb 2020
This file is part of the GNUstep Project
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public
License along with this program; see the file COPYINGv3.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// #import "common.h"
#include <string.h>
#import "Foundation/NSArray.h"
#import "Foundation/NSAutoreleasePool.h"
#import "Foundation/NSData.h"
#import "Foundation/NSDictionary.h"
#import "Foundation/NSException.h"
#import "Foundation/NSFileHandle.h"
#import "Foundation/NSProcessInfo.h"
#import "Foundation/NSPropertyList.h"
#import "Foundation/NSString.h"
#import "Foundation/NSUserDefaults.h"
#import "Foundation/NSValue.h"
#import "NSPropertyList+PLUtil.h"
// From NSPropertyList.m
extern void
GSPropertyListMake(id, NSDictionary *, BOOL, BOOL, unsigned, id *);
// We don't have @[] on gcc
#define NARRAY(...) [NSArray arrayWithObjects: __VA_ARGS__, nil]
// And no @() or @123
#define NINT(Num) [NSNumber numberWithInt: Num]
// Unfortunately we have to define @() for @"" too because a macro later
#define NSTR(Str) [NSString stringWithCString: Str]
/* Bitmap of 'quotable' characters ... those characters which must be
* inside a quoted string if written to an old style property list.
* Taken from NSPropertyList.m.
*/
static const unsigned char quotables[32] = {
'\xff', '\xff', '\xff', '\xff', '\x85', '\x13', '\x00', '\x78',
'\x00', '\x00', '\x00', '\x38', '\x01', '\x00', '\x00', '\xa8',
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
};
#define IS_BIT_SET(a, i) ((((a) & (1 << (i)))) > 0)
#define GS_IS_QUOTABLE(X) IS_BIT_SET(quotables[(X) / 8], (X) % 8)
/**
* Indexes a NSArray or a NSDictionary.
*/
id
plIndex(id obj, NSString *key)
{
const char *ckey;
char * endptr = NULL;
NSInteger res;
if ([obj isKindOfClass: [NSDictionary class]])
{
return [(NSDictionary *) obj objectForKey: key];
}
else if ([obj isKindOfClass: [NSArray class]])
{
ckey = [key cStringUsingEncoding: [NSString defaultCStringEncoding]];
res = strtoll(ckey, &endptr, 10);
if (endptr && *endptr != '\0')
{
[NSException raise: NSInvalidArgumentException
format: @"%@ is not a valid integer", key];
}
return [(NSArray *) obj objectAtIndex: res];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"%@ is not indexible", obj];
return nil;
}
}
/**
* Mutate obj[key] to leaf.
* If leaf is nil, remove.
* Else if replace is NO, insert.
* Otherwise replace.
*
* Inserting and replacing are the same for NSMutableDictionary.
*/
void
mutate(id obj, NSString *key, id leaf, BOOL replace)
{
const char *ckey;
char * endptr = NULL;
NSInteger res;
if ([obj isKindOfClass: [NSMutableDictionary class]])
{
if (!leaf)
[(NSMutableDictionary *) obj removeObjectForKey: key];
else
[(NSMutableDictionary *) obj setObject: leaf forKey: key];
}
else if ([obj isKindOfClass: [NSMutableArray class]])
{
ckey = [key cStringUsingEncoding: [NSString defaultCStringEncoding]];
res = strtoll(ckey, &endptr, 10);
if (endptr && *endptr != '\0')
{
[NSException raise: NSInvalidArgumentException
format: @"%@ is not a valid integer", key];
}
if (!leaf)
[(NSMutableArray *) obj removeObjectAtIndex: res];
else if (replace)
[(NSMutableArray *) obj replaceObjectAtIndex: res withObject: leaf];
else
[(NSMutableArray *) obj insertObject: leaf atIndex: res];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"%@ is not indexible", obj];
}
}
#define KEYPATH_SEP '.'
NSString *
parseQuotedString(const char *, size_t *);
/**
* Parses a keypath to its component keys. ISO/IEC 14977 EBNF:
* <pre>
* keypath = '' | keypath '.' key;
* key = quotedString | unquotedStringNotAllowingPeriod;
* </pre>
* The definitions of strings follow plist conventions.
* The use of quoted strings is a GNUstep extension (I think).
*/
NSArray *
parseKeyPath(const char *keypath)
{
NSMutableArray *res = [[NSMutableArray alloc] init];
NSString * key = nil;
size_t i;
size_t j;
for (i = 0; keypath[i]; i++)
switch (keypath[i])
{
case KEYPATH_SEP:
[res addObject: key];
key = nil;
break;
case '"':
key = parseQuotedString(keypath, &i);
break;
default:
for (j = i; keypath[j] && !GS_IS_QUOTABLE(keypath[j])
&& keypath[j] != KEYPATH_SEP;
j++)
;
key = [NSString stringWithCString: &keypath[i] length: (j - i)];
i = j - 1;
break;
}
return [res copy];
}
/**
* Parse a quoted string by pretending it is a plist.
*/
NSString *
parseQuotedString(const char *keypath, size_t *i)
{
const char *begin = &keypath[*i];
const char *end;
id parsed;
// Select the part of the quoted string that looks like a plist string
for (end = begin + 1; *end && *end != '"'; end++)
if (*end == '\\')
{
if (end[1])
end += 1;
else
[NSException raise: NSInvalidArgumentException
format: @"Premature EOF in keypath"];
}
if (!end)
[NSException raise: NSInvalidArgumentException
format: @"Premature EOF in keypath"];
*i = end - keypath + 1;
parsed = [[NSString stringWithCString: begin length: end - begin] propertyList];
return (NSString *) parsed;
}
/**
* Index by keypath.
*/
id
plIndexKeypath(id obj, NSString *keypath, int depthOffset)
{
NSArray *parsedPath = parseKeyPath([keypath cString]);
int count = [parsedPath count];
int i;
for (i = 0; i < count - depthOffset; i++)
obj = plIndex(obj, [parsedPath objectAtIndex: i]);
return obj;
}
/**
* Interpret -type value options.
*
* The -plist type is a GNUStep extension.
*/
id
parseValue(NSString *type, NSString *value)
{
if ([type isEqual: @"-plist"])
return [value propertyList];
else if ([type isEqual: @"-xml"] || [type isEqual: @"-date"])
{
NSData *mydata =
[value dataUsingEncoding: [NSString defaultCStringEncoding]];
NSPropertyListFormat aFormat;
NSError * anError;
id result = [NSPropertyListSerialization
propertyListWithData: mydata
options: NSPropertyListMutableContainersAndLeaves
format: &aFormat
error: &anError];
if (result == nil)
{
GSPrintf(stderr, @"Parsing plist %@: %@\n", value, anError);
return nil;
}
else if ([type isEqual: @"-xml"]
&& aFormat != NSPropertyListXMLFormat_v1_0)
GSPrintf(stderr,
@"Warning: parsing XML plist %@: Not an XML (fmt %d)\n", value,
aFormat);
else if ([type isEqual: @"-date"]
&& ![result isKindOfClass: [NSDate class]])
GSPrintf(stderr, @"Warning: parsing date %@: Not a date (got %@)\n",
value, result);
return result;
}
else if ([type isEqual: @"-bool"])
return [NSNumber
numberWithBool: ([value isEqual: @"YES"] || [value isEqual: @"true"])];
else if ([type isEqual: @"-integer"])
return [[NSNumber alloc] initWithLongLong: [value longLongValue]];
else if ([type isEqual: @"-float"])
// We do a step further than NSPropertyList.m and probably Apple,
// since notsupporting inf and nan is a bad look
// (No hex literals for now unless someone really wants it)
return [[NSNumber alloc] initWithDouble: strtod([value cString], 0)];
else if ([type isEqual: @"-data"])
return [[NSData alloc]
initWithBase64EncodedData: [value
dataUsingEncoding: [NSString
defaultCStringEncoding]]
options: NSDataBase64DecodingIgnoreUnknownCharacters];
else
GSPrintf(stderr, @"Unrecognized type %@\n", type);
return nil;
}
#define SELFMAP(Name) NINT(Name), NSTR(#Name)
/**
* Translates a string fmt to NSPropertyListFormat.
*/
NSPropertyListFormat
plFormatFromName(NSString *name)
{
// clang-format off
NSDictionary *nameMap = [NSDictionary dictionaryWithObjectsAndKeys:
NINT(NSPropertyListXMLFormat_v1_0), @"xml1",
NINT(NSPropertyListBinaryFormat_v1_0), @"binary1",
NINT(NSPropertyListOpenStepFormat), @"openstep",
NINT(NSPropertyListGNUstepFormat), @"gnustep",
NINT(NSPropertyListGNUstepBinaryFormat), @"gsbinary",
NINT(NSPropertyListJSONFormat), @"json",
SELFMAP(NSPropertyListOpenStepFormat),
SELFMAP(NSPropertyListXMLFormat_v1_0),
SELFMAP(NSPropertyListBinaryFormat_v1_0),
SELFMAP(NSPropertyListGNUstepFormat),
SELFMAP(NSPropertyListGNUstepBinaryFormat),
nil];
id res = [nameMap objectForKey: name];
// clang-format on
if (!res)
[NSException raise: NSInvalidArgumentException
format: @"Invalid fmt %@", name];
return [res intValue];
}
/**
* Dumps obj to outfile.
*/
int
dumpToFile(id obj, NSPropertyListFormat fmt, NSString *outfile)
{
NSString *errorString = nil;
NSFileHandle *fh;
NSData *outdata =
[NSPropertyListSerialization dataFromPropertyList: obj
format: fmt
errorDescription: &errorString];
if (errorString)
{
GSPrintf(stderr, @"Dumping %@ as format %@ - %@\n", obj, fmt,
errorString);
return EXIT_FAILURE;
}
if ([outfile isEqual: @"-"])
fh = [NSFileHandle fileHandleWithStandardOutput];
else
fh = [NSFileHandle fileHandleForWritingAtPath: outfile];
[fh writeData: outdata];
[fh synchronizeFile];
return EXIT_SUCCESS;
}
int
plCmdConvert(id obj, NSArray *cmdargs, NSString *outfile)
{
NSString *fmt = [cmdargs objectAtIndex: 0];
return dumpToFile(obj, plFormatFromName(fmt), outfile);
}
int
plCmdExtract(id obj, NSArray *cmdargs, NSString *outfile)
{
NSString *keypath = [cmdargs objectAtIndex: 0];
NSString *fmt = [cmdargs objectAtIndex: 1];
obj = plIndexKeypath(obj, keypath, 0);
return dumpToFile(obj, plFormatFromName(fmt), outfile);
}
int
plCmdRemove(id obj, NSPropertyListFormat fmt, NSArray *cmdargs,
NSString *outfile)
{
NSString *keypath = [cmdargs objectAtIndex: 0];
NSArray *parsedPath = parseKeyPath([keypath cString]);
id leaf = plIndexKeypath(obj, keypath, 1);
mutate(leaf, [parsedPath lastObject], nil, false);
return dumpToFile(obj, fmt, outfile);
}
int
plCmdInsert(id obj, NSPropertyListFormat fmt, NSArray *cmdargs,
NSString *outfile)
{
NSString *keypath = [cmdargs objectAtIndex: 0];
id newleaf = parseValue([cmdargs objectAtIndex: 1], [cmdargs objectAtIndex: 2]);
NSArray *parsedPath = parseKeyPath([keypath cString]);
id leaf = plIndexKeypath(obj, keypath, 1);
if (!newleaf)
return EXIT_FAILURE;
mutate(leaf, [parsedPath lastObject], newleaf, false);
return dumpToFile(obj, fmt, outfile);
}
int
plCmdReplace(id obj, NSPropertyListFormat fmt, NSArray *cmdargs,
NSString *outfile)
{
NSString *keypath = [cmdargs objectAtIndex: 0];
id newleaf = parseValue([cmdargs objectAtIndex: 1], [cmdargs objectAtIndex: 2]);
NSArray *parsedPath = parseKeyPath([keypath cString]);
id leaf = plIndexKeypath(obj, keypath, 1);
if (!newleaf)
return EXIT_FAILURE;
mutate(leaf, [parsedPath lastObject], newleaf, true);
return dumpToFile(obj, fmt, outfile);
}
static void
print_help(FILE *f)
{
GSPrintf(f, @"Property list utility\n");
GSPrintf(f, @"Usage: plutil [command] [options] file\n\n");
GSPrintf(f, @"Accepted commands:\n");
GSPrintf(
f, @" -p\tPrints the plists in a human-readable form (GNUstep ASCII).\n");
GSPrintf(f, @"Accepted options:\n");
}
typedef enum _Action
{
ACTION_LINT,
ACTION_PRINT,
ACTION_CONVERT,
ACTION_REPLACE,
ACTION_INSERT,
ACTION_REMOVE,
ACTION_EXTRACT,
} Action;
/** <p> Property list utility. Should act like macOS catalina plutil(1).
* </p>
*/
int
main(int argc, char **argv, char **env)
{
int status = EXIT_SUCCESS;
do
{
ENTER_POOL
NSProcessInfo *proc;
NSArray *args;
NSString *arg;
NSString *inpath;
NSArray *cmdargs = nil;
NSDictionary *commands = nil;
NSArray *command_rhs;
NSString *outpath = nil;
NSString *outext = nil;
Action action = ACTION_LINT;
int count = 0;
int i = 1;
#ifdef GS_PASS_ARGUMENTS
GSInitializeProcess(argc, argv, env);
#endif
proc = [NSProcessInfo processInfo];
if (proc == nil)
{
NSLog(@"plutil: unable to get process information.");
status = EXIT_FAILURE;
break;
}
args = [proc arguments];
if ((count = [args count]) <= 1)
{
NSLog(@"plutil: no files given.");
status = EXIT_FAILURE;
break;
}
// Parse the COMMAND.
// Maps number of args to commands.
// clang-format off
commands = [NSDictionary dictionaryWithObjectsAndKeys:
NARRAY(NINT(ACTION_PRINT), NINT(0)), @"-p",
NARRAY(NINT(ACTION_LINT), NINT(0)), @"-lint",
NARRAY(NINT(ACTION_CONVERT), NINT(1)), @"-convert",
NARRAY(NINT(ACTION_INSERT), NINT(3)), @"-insert",
NARRAY(NINT(ACTION_REPLACE), NINT(3)), @"-replace",
NARRAY(NINT(ACTION_REMOVE), NINT(1)), @"-remove",
NARRAY(NINT(ACTION_EXTRACT), NINT(2)), @"-extract",
nil];
// clang-format on
NS_DURING
{
NSData * fileData;
NSPropertyListFormat aFormat;
NSError * anError;
id result;
NSMutableString * outStr = nil;
NSDictionary * locale;
arg = [args objectAtIndex: i];
if (![arg hasPrefix: @"-"])
goto parse_file;
command_rhs = [commands objectForKey: arg];
if (command_rhs)
{
int iwant;
NSRange argrange;
action = [[command_rhs objectAtIndex: 0] intValue];
iwant = [[command_rhs objectAtIndex: 1] intValue];
argrange.location = i + 1;
argrange.length = iwant;
cmdargs = [args subarrayWithRange: argrange];
i += 1 + iwant;
}
// Parse options
for (; i < count; i++)
{
arg = [args objectAtIndex: i];
if (![arg hasPrefix: @"-"]
|| [arg isEqual: @"-"]
|| [arg isEqual: @"--"])
{
goto parse_file;
}
else if ([arg isEqual: @"-help"])
{
print_help(stdout);
break;
}
else if ([arg isEqual: @"-s"])
{
/* NOOP: What the heck is being quiet? */;
}
else if ([arg isEqual: @"-o"])
{
outpath = [args objectAtIndex: ++i];
}
else if ([arg isEqual: @"-e"])
{
outext = [args objectAtIndex: ++i];
}
else
{
[NSException raise: NSInvalidArgumentException
format: @"Invalid option %@", arg];
}
}
parse_file:
inpath = [args objectAtIndex: i];
if (!outpath && !outext && action != ACTION_EXTRACT)
{
outpath = inpath;
}
else if (outext)
{
NSRange dot;
dot = [inpath rangeOfString: @"." options: NSBackwardsSearch];
if (dot.length == 0)
{
dot.location = [inpath length];
}
outpath = [NSString stringWithFormat: @"%@.%@",
[inpath substringToIndex: dot.location], outext];
}
// Open, read, do things.
if ([inpath isEqual: @"-"])
{
NSFileHandle *fh = [NSFileHandle fileHandleWithStandardInput];
fileData = [fh readDataToEndOfFile];
}
else
fileData = [NSData dataWithContentsOfFile: inpath];
result = [NSPropertyListSerialization
propertyListWithData: fileData
options: NSPropertyListMutableContainersAndLeaves
format: &aFormat
error: &anError];
if (result == nil)
{
GSPrintf(stderr, @"Loading '%@' - %@\n", inpath, anError);
status = EXIT_FAILURE;
break;
}
switch (action)
{
case ACTION_LINT:
break;
case ACTION_PRINT:
// Not using description because we can GS it
locale =
[[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
GSPropertyListMake(result, locale, NO, NO, 2, &outStr);
GSPrintf(stdout, @"%@\n", outStr);
break;
case ACTION_CONVERT:
status = plCmdConvert(result, cmdargs, outpath);
break;
case ACTION_REPLACE:
status = plCmdReplace(result, aFormat, cmdargs, outpath);
break;
case ACTION_INSERT:
status = plCmdInsert(result, aFormat, cmdargs, outpath);
break;
case ACTION_REMOVE:
status = plCmdRemove(result, aFormat, cmdargs, outpath);
break;
case ACTION_EXTRACT:
if (!outpath)
outpath = @"-";
status = plCmdExtract(result, cmdargs, outpath);
break;
}
}
NS_HANDLER
{
NSLog(@"Problem: %@", localException);
if ([[localException name] isEqual: NSInvalidArgumentException])
print_help(stderr);
status = EXIT_FAILURE;
break;
}
NS_ENDHANDLER
LEAVE_POOL
} while (0);
return status;
}