Revision: 22455
          http://sourceforge.net/p/bibdesk/svn/22455
Author:   hofman
Date:     2018-07-23 12:09:33 +0000 (Mon, 23 Jul 2018)
Log Message:
-----------
Allow escaped character specifiers in optional arguments in format

Modified Paths:
--------------
    trunk/bibdesk/BDSKFormatParser.m

Modified: trunk/bibdesk/BDSKFormatParser.m
===================================================================
--- trunk/bibdesk/BDSKFormatParser.m    2018-07-23 06:30:23 UTC (rev 22454)
+++ trunk/bibdesk/BDSKFormatParser.m    2018-07-23 12:09:33 UTC (rev 22455)
@@ -64,8 +64,10 @@
 static NSCharacterSet *validOptArg3SpecifierChars = nil;
 static NSCharacterSet *validOptArg2SpecifierChars = nil;
 static NSCharacterSet *validAuthorSpecifierChars = nil;
+static NSCharacterSet *optArgStopChars = nil;
 static NSDictionary *specAttr = nil;
 static NSDictionary *paramAttr = nil;
+static NSDictionary *paramTextAttr = nil;
 static NSDictionary *argAttr = nil;
 static NSDictionary *textAttr = nil;
 static NSDictionary *errorAttr = nil;
@@ -79,6 +81,26 @@
     return NO;
 }
 
+static BOOL scanOptArg(NSScanner *scanner, NSString **result) {
+    NSMutableString *tmpString = nil;
+    NSString *string = nil;
+    unichar escapeChar;
+    while (YES) {
+        if ([scanner scanUpToCharactersFromSet:optArgStopChars 
intoString:&string] && tmpString != nil)
+            [tmpString appendString:string];
+        if ([scanner scanString:@"%" intoString:NULL] == NO || [scanner 
scanCharacter:&escapeChar] == NO)
+            break;
+        if (tmpString == nil)
+            tmpString = [NSMutableString stringWithString:string ?: @""];
+        [tmpString appendFormat:@"%C", escapeChar];
+    }
+    if ([tmpString length] == 0 && [string length] == 0)
+        return NO;
+    if (result)
+        *result = tmpString ?: string;
+    return YES;
+}
+
 + (void)initialize {
     BDSKINITIALIZE;
     
@@ -92,11 +114,13 @@
     validOptArg3SpecifierChars = [[NSCharacterSet 
characterSetWithCharactersInString:@"APws"] retain];
     validOptArg2SpecifierChars = [[NSCharacterSet 
characterSetWithCharactersInString:@"apk"] retain];
     validAuthorSpecifierChars = [[NSCharacterSet 
characterSetWithCharactersInString:@"aApP"] retain];
-    
+    optArgStopChars = [[NSCharacterSet 
characterSetWithCharactersInString:@"%]"] retain];
+
     NSFont *font = [NSFont systemFontOfSize:0];
     NSFont *boldFont = [NSFont boldSystemFontOfSize:0];
     specAttr = [[NSDictionary alloc] initWithObjectsAndKeys:boldFont, 
NSFontAttributeName, [NSColor blueColor], NSForegroundColorAttributeName, nil];
     paramAttr = [[NSDictionary alloc] initWithObjectsAndKeys:boldFont, 
NSFontAttributeName, [NSColor colorWithCalibratedRed:0.0 green:0.5 blue:0.0 
alpha:1.0], NSForegroundColorAttributeName, nil];
+    paramTextAttr = [[NSDictionary alloc] initWithObjectsAndKeys:boldFont, 
NSFontAttributeName, [NSColor colorWithCalibratedRed:0.0 green:0.7 blue:0.0 
alpha:1.0], NSForegroundColorAttributeName, nil];
     argAttr = [[NSDictionary alloc] initWithObjectsAndKeys:font, 
NSFontAttributeName, [NSColor controlTextColor], 
NSForegroundColorAttributeName, nil];
     textAttr = [[NSDictionary alloc] initWithObjectsAndKeys:boldFont, 
NSFontAttributeName, [NSColor controlTextColor], 
NSForegroundColorAttributeName, nil];
     errorAttr = [[NSDictionary alloc] initWithObjectsAndKeys:font, 
NSFontAttributeName, [NSColor redColor], NSForegroundColorAttributeName, nil];
@@ -150,11 +174,11 @@
                                        if (NO == [scanner isAtEnd]) {
                                                // look for [separator]
                                                if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                                       if (NO == [scanner 
scanUpToString:@"]" intoString:&authSep]) authSep = @"";
+                                                       if (NO == 
scanOptArg(scanner, &authSep)) authSep = @"";
                                                        [scanner 
scanString:@"]" intoString:NULL];
                                                        // look for [etal]
                                                        if ([scanner 
scanString:@"[" intoString:NULL]) {
-                                                               if (NO == 
[scanner scanUpToString:@"]" intoString:&etal]) etal = @"";
+                                                               if (NO == 
scanOptArg(scanner, &etal)) etal = @"";
                                                                [scanner 
scanString:@"]" intoString:NULL];
                                                        }
                                                }
@@ -222,15 +246,15 @@
                                        if (NO == [scanner isAtEnd]) {
                                                // look for [author separator]
                                                if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                                       if (NO == [scanner 
scanUpToString:@"]" intoString:&authSep]) authSep = @"";
+                                                       if (NO == 
scanOptArg(scanner, &authSep)) authSep = @"";
                                                        [scanner 
scanString:@"]" intoString:NULL];
                                                        // look for [name 
separator]
                                                        if ([scanner 
scanString:@"[" intoString:NULL]) {
-                                                               if (NO == 
[scanner scanUpToString:@"]" intoString:&nameSep]) nameSep = @"";
+                                                               if (NO == 
scanOptArg(scanner, &nameSep)) nameSep = @"";
                                                                [scanner 
scanString:@"]" intoString:NULL];
                                                                // look for 
[etal]
                                                                if ([scanner 
scanString:@"[" intoString:NULL]) {
-                                                                       if (NO 
== [scanner scanUpToString:@"]" intoString:&etal]) etal = @"";
+                                                                       if (NO 
== scanOptArg(scanner, &etal)) etal = @"";
                                                                        
[scanner scanString:@"]" intoString:NULL];
                                                                }
                                                        }
@@ -317,7 +341,7 @@
                     NSString *numString = nil;
                     NSString *title = [pub title];
                     if ([scanner scanString:@"[" intoString:NULL]) {
-                        if ([scanner scanUpToString:@"]" 
intoString:&numString])
+                        if (scanOptArg(scanner, &numString))
                             smallWordLength = (NSUInteger)[numString 
integerValue];
                         else
                             smallWordLength = 0;
@@ -410,10 +434,10 @@
                                        NSString *slash = (isLocalFile) ? @"-" 
: @"/";
                                        NSString *sep = nil;
                                        if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                               if (NO == [scanner 
scanUpToString:@"]" intoString:&slash]) slash = @"";
+                                               if (NO == scanOptArg(scanner, 
&slash)) slash = @"";
                                                [scanner scanString:@"]" 
intoString:NULL];
                         if ([scanner scanString:@"[" intoString:NULL]) {
-                            if (NO == [scanner scanUpToString:@"]" 
intoString:&sep]) sep = @"";
+                            if (NO == scanOptArg(scanner, &sep)) sep = @"";
                             [scanner scanString:@"]" intoString:NULL];
                         }
                                        }
@@ -508,7 +532,7 @@
                        // old file extension without period
                     NSString *defaultExt = @"";
                                        if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                               if (NO == [scanner 
scanUpToString:@"]" intoString:&defaultExt]) defaultExt = @"";
+                                               if (NO == scanOptArg(scanner, 
&defaultExt)) defaultExt = @"";
                                                [scanner scanString:@"]" 
intoString:NULL];
                                        }
                                        NSString *filename = nil;
@@ -549,7 +573,7 @@
                                                [scanner scanString:@"}" 
intoString:NULL]) {
                                                // look for [slash]
                                                if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                                       if (NO == [scanner 
scanUpToString:@"]" intoString:&slash]) slash = @"";
+                                                       if (NO == 
scanOptArg(scanner, &slash)) slash = @"";
                                                        [scanner 
scanString:@"]" intoString:NULL];
                                                }
                         
@@ -590,14 +614,14 @@
                                                [scanner scanString:@"}" 
intoString:NULL]) {
                         // look for [sep]
                         if ([scanner scanString:@"[" intoString:NULL]) {
-                            if (NO == [scanner scanUpToString:@"]" 
intoString:&sepChars]) sepChars = @" ";
+                            if (NO == scanOptArg(scanner, &sepChars)) sepChars 
= @" ";
                             [scanner scanString:@"]" intoString:NULL];
                             // look for [slash]
                             if ([scanner scanString:@"[" intoString:NULL]) {
-                                if (NO == [scanner scanUpToString:@"]" 
intoString:&slash]) slash = @"";
+                                if (NO == scanOptArg(scanner, &slash)) slash = 
@"";
                                 [scanner scanString:@"]" intoString:NULL];
                                 if ([scanner scanString:@"[" intoString:NULL]) 
{
-                                    if (NO == [scanner scanUpToString:@"]" 
intoString:&sep]) sep = @"";
+                                    if (NO == scanOptArg(scanner, &sep)) sep = 
@"";
                                     [scanner scanString:@"]" intoString:NULL];
                                 }
                             }
@@ -674,15 +698,15 @@
                                                [scanner scanString:@"}" 
intoString:NULL]) {
                                                // look for [yes value]
                                                if ([scanner scanString:@"[" 
intoString:NULL]) {
-                                                       if (NO == [scanner 
scanUpToString:@"]" intoString:&yesValue]) yesValue = @"";
+                                                       if (NO == 
scanOptArg(scanner, &yesValue)) yesValue = @"";
                                                        [scanner 
scanString:@"]" intoString:NULL];
                             // look for [no value]
                             if ([scanner scanString:@"[" intoString:NULL]) {
-                                if (NO == [scanner scanUpToString:@"]" 
intoString:&noValue]) noValue = @"";
+                                if (NO == scanOptArg(scanner, &noValue)) 
noValue = @"";
                                 [scanner scanString:@"]" intoString:NULL];
                                 // look for [mixed value]
                                 if ([scanner scanString:@"[" intoString:NULL]) 
{
-                                    if (NO == [scanner scanUpToString:@"]" 
intoString:&mixedValue]) mixedValue = @"";
+                                    if (NO == scanOptArg(scanner, 
&mixedValue)) mixedValue = @"";
                                     [scanner scanString:@"]" intoString:NULL];
                                 }
                             }
@@ -786,7 +810,7 @@
                                                prefixStr = parsedStr;
                                                parsedStr = [NSMutableString 
string];
                         if ([scanner scanString:@"[" intoString:NULL]) {
-                            [scanner scanUpToString:@"]" 
intoString:&uniqueSeparator];
+                            scanOptArg(scanner, &uniqueSeparator);
                             [scanner scanString:@"]" intoString:NULL];
                         }
                                                if (NO == [scanner 
scanUnsignedInteger:&uniqueNumber]) uniqueNumber = 1;
@@ -1111,16 +1135,38 @@
                        if (NO == [scanner isAtEnd]) {
                                NSInteger i, numOpts = 
([validOptArg3SpecifierChars characterIsMember:specifier] ? 3 : 
[validOptArg2SpecifierChars characterIsMember:specifier] ? 2 : 1);
                                for (i = 0; i < numOpts && [scanner 
scanString:@"[" intoString: NULL]; i++) {
-                                       if (NO == [scanner scanUpToString:@"]" 
intoString:&string]) 
-                                               string = @"";
+                    NSMutableString *optArgString = [NSMutableString string];
+                    while (YES) {
+                        if ([scanner scanUpToCharactersFromSet:optArgStopChars 
intoString:&string]) {
+                            if (specifier != 'w' || i > 0)
+                                string = [self stringBySanitizingString:string 
forField:fieldName];
+                            [optArgString appendString:string];
+                        }
+                        if ([scanner scanString:@"%" intoString:NULL] == NO)
+                            break;
+                        unichar escapeChar;
+                        if ([scanner scanCharacter:&escapeChar] == NO) {
+                            errorMsg = NSLocalizedString(@"Empty specifier % 
at end of format.", @"Error description");
+                            break;
+                        }
+                        else if ([validEscapeSpecifierChars 
characterIsMember:escapeChar] == NO) {
+                            errorMsg = [NSString 
stringWithFormat:NSLocalizedString(@"Invalid specifier %%%C in format.", 
@"Error description"), escapeChar];
+                            break;
+                        }
+                        else if ([invalidCharSet 
characterIsMember:escapeChar]) {
+                            errorMsg = [NSString stringWithFormat: 
NSLocalizedString(@"Invalid escape specifier %%%C in format.", @"Error 
description"), escapeChar];
+                            break;
+                        }
+                        [optArgString appendFormat:@"%%%C", escapeChar];
+                    }
+                    if (errorMsg != nil)
+                        break;
                                        if (NO == [scanner scanString:@"]" 
intoString:NULL]) {
                                                errorMsg = [NSString 
stringWithFormat: NSLocalizedString(@"Missing \"]\" after specifier %%%C.", 
@"Error description"), specifier];
                                                break;
                                        }
-                    if (specifier != 'w' || i > 0)
-                        string = [self stringBySanitizingString:string 
forField:fieldName];
                                        AppendStringToFormatStrings(@"[", 
paramAttr);
-                                       AppendStringToFormatStrings(string, 
paramAttr);
+                                       
AppendStringToFormatStrings(optArgString, paramTextAttr);
                                        AppendStringToFormatStrings(@"]", 
paramAttr);
                                }
                                if (errorMsg != nil)

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to