mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Merge branch 'master' into nsurl-additions
This commit is contained in:
commit
17af685b1a
32 changed files with 1152 additions and 111 deletions
77
.clang-format
Normal file
77
.clang-format
Normal 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:
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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);\
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
{
|
||||
case 1:
|
||||
[pnc setNickname: [nameArray objectAtIndex: 0]];
|
||||
break;
|
||||
case 2:
|
||||
[pnc setGivenName: [nameArray objectAtIndex: 0]];
|
||||
[pnc setFamilyName: [nameArray objectAtIndex: 1]];
|
||||
|
|
|
@ -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]];
|
||||
|
|
|
@ -74,7 +74,8 @@
|
|||
#endif
|
||||
|
||||
|
||||
NSString * const NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
|
||||
NSRunLoopMode const NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
|
||||
NSRunLoopMode const NSRunLoopCommonModes = @"NSRunLoopCommonModes";
|
||||
|
||||
static NSDate *theFuture = nil;
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
47
Tools/NSPropertyList+PLUtil.h
Normal file
47
Tools/NSPropertyList+PLUtil.h
Normal 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
|
122
Tools/NSPropertyList+PLUtil.m
Normal file
122
Tools/NSPropertyList+PLUtil.m
Normal 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
|
|
@ -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.
|
||||
|
|
|
@ -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
630
Tools/plutil.m
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue