source: trunk/Cocoa/Pester/Source/NJRDateFormatter.m@ 360

Last change on this file since 360 was 360, checked in by Nicholas Riley, 15 years ago

Pester.xcodeproj: Add Perl embedding bits; remove SoundFileManager.h.

DynaLoader.a: i386/ppc version from Tiger; Leopard's version causes
Tiger to crash.

Info-Pester.plist: Updated copyright date.

Read Me.rtfd: Remove .typeAttributes.dict, no longer used; update a
bit.

PSTimeDateEditor.m: Switch to NJRDateFormatters again.

NJRDateFormatter.[hm]: Removed old-style date formatter workarounds;
added code for using Date::Manip and trying multiple ICU-based date
formatters.

English.lproj/InfoPlist.strings: Updated copyright date.

English.lproj/MainMenu.nib: Modified date completion menu for items
Date::Manip can parse.

Manip.pm: Date::Manip 5.47, converted to UTF-8.

File size: 6.0 KB
Line 
1//
2// NJRDateFormatter.m
3// Pester
4//
5// Created by Nicholas Riley on Wed Oct 09 2002.
6// Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "NJRDateFormatter.h"
10
11// generated by perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
12#include <EXTERN.h>
13#include <perl.h>
14
15EXTERN_C void xs_init (pTHX);
16
17EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
18
19EXTERN_C void
20xs_init(pTHX)
21{
22 char *file = __FILE__;
23 dXSUB_SYS;
24
25 /* DynaLoader is a special case */
26 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
27}
28// end generated code
29
30static PerlInterpreter *my_perl;
31static NSDateFormatter *dateManipFormatter;
32
33static NSDate *parse_natural_language_date(NSString *input) {
34 if (my_perl == NULL) return nil;
35
36 if ([input rangeOfString: @"|"].length > 0) {
37 NSMutableString *sanitized = [[input mutableCopy] autorelease];
38 [sanitized replaceOccurrencesOfString: @"|" withString: @""
39 options: NSLiteralSearch
40 range: NSMakeRange(0, [sanitized length])];
41 input = sanitized;
42 }
43
44 NSString *temp = [[NSString alloc] initWithFormat: @"UnixDate(q|%@|, '%%q')", input];
45 NSLog(@"%@", temp);
46 SV *d = eval_pv([temp UTF8String], TRUE);
47 [temp release];
48 if (d == NULL) return nil;
49
50 STRLEN s_len;
51 char *s = SvPV(d, s_len);
52 if (s == NULL || s_len == 0) return nil;
53
54 NSDate *date = [dateManipFormatter dateFromString: [NSString stringWithUTF8String: s]];
55 NSLog(@"%@", date);
56
57 return date;
58}
59
60static void init_perl(void) {
61 const char *argv[] = {"", "-CSD", "-I", "", "-MDate::Manip", "-e", "0"};
62 argv[3] = [[[NSBundle mainBundle] resourcePath] fileSystemRepresentation];
63 PERL_SYS_INIT(0, NULL);
64 my_perl = perl_alloc();
65 if (my_perl == NULL) return;
66
67 perl_construct(my_perl);
68 if (perl_parse(my_perl, xs_init, 7, (char **)argv, NULL) != 0) goto fail;
69
70 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
71 if (perl_run(my_perl) != 0) goto fail;
72
73 // XXX detect localization changes
74 eval_pv("Date_Init(\"Language=English\", \"DateFormat=non-US\", \"Internal=1\"", TRUE);
75
76 if (parse_natural_language_date(@"tomorrow") == nil) goto fail;
77
78 return;
79
80fail:
81 perl_destruct(my_perl);
82 perl_free(my_perl);
83 PERL_SYS_TERM();
84 my_perl = NULL;
85}
86
87// workaround for bug in Jaguar (and earlier?) NSCalendarDate dateWithNaturalLanguageString:
88NSString *stringByRemovingSurroundingWhitespace(NSString *string) {
89 static NSCharacterSet *nonWhitespace = nil;
90 NSRange firstValidCharacter, lastValidCharacter;
91
92 if (!nonWhitespace) {
93 nonWhitespace = [[[NSCharacterSet characterSetWithCharactersInString:
94 @" \t\r\n"] invertedSet] retain];
95 }
96
97 firstValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace];
98 if (firstValidCharacter.length == 0)
99 return @"";
100 lastValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace options: NSBackwardsSearch];
101
102 if (firstValidCharacter.location == 0 && lastValidCharacter.location == [string length] - 1)
103 return string;
104 else
105 return [string substringWithRange: NSUnionRange(firstValidCharacter, lastValidCharacter)];
106}
107
108static const NSDateFormatterStyle formatterStyles[] = {
109 NSDateFormatterShortStyle,
110 NSDateFormatterMediumStyle,
111 NSDateFormatterLongStyle,
112 NSDateFormatterFullStyle,
113 NSDateFormatterNoStyle
114};
115
116@implementation NJRDateFormatter
117
118#pragma mark initialize-release
119
120+ (void)initialize;
121{
122 dateManipFormatter = [[NSDateFormatter alloc] init];
123 [dateManipFormatter setDateFormat: @"yyyyMMddHHmmss"]; // Date::Manip's "%q"
124 init_perl();
125}
126
127+ (NJRDateFormatter *)dateFormatter;
128{
129 NJRDateFormatter *formatter = [[self alloc] init];
130 NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
131
132 for (NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
133 NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
134 [tryFormatter setLenient: YES];
135 [tryFormatter setTimeStyle: NSDateFormatterNoStyle];
136 [tryFormatter setDateStyle: *s];
137 [tryFormatters addObject: tryFormatter];
138 [tryFormatter release];
139 }
140 // XXX do this in init
141 formatter->tryFormatters = tryFormatters;
142
143 return [formatter autorelease];
144}
145
146+ (NJRDateFormatter *)timeFormatter;
147{
148 NJRDateFormatter *formatter = [[self alloc] init];
149 NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
150
151 for (NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
152 NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
153 [tryFormatter setLenient: YES];
154 [tryFormatter setTimeStyle: *s];
155 [tryFormatter setDateStyle: NSDateFormatterNoStyle];
156 [tryFormatters addObject: tryFormatter];
157 [tryFormatter release];
158 }
159 formatter->tryFormatters = tryFormatters;
160
161 return [formatter autorelease];
162}
163
164- (void)dealloc;
165{
166 [tryFormatters release]; tryFormatters = nil;
167 [super dealloc];
168}
169
170#pragma mark primitive formatter
171
172- (NSString *)stringForObjectValue:(id)obj;
173{
174 return [super stringForObjectValue: obj];
175}
176
177- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs;
178{
179 return [super attributedStringForObjectValue: obj
180 withDefaultAttributes: attrs];
181}
182
183- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
184{
185 if ([super getObjectValue: anObject forString: string errorDescription: error])
186 return YES;
187
188 NSDate *date;
189 NSEnumerator *e = [tryFormatters objectEnumerator];
190 NSDateFormatter *tryFormatter;
191
192 // XXX untested; does this work?
193 while ( (tryFormatter = [e nextObject]) != nil) {
194 date = [tryFormatter dateFromString: string];
195 if (date != nil) goto success;
196 }
197
198 date = parse_natural_language_date(string);
199 if (date != nil) goto success;
200
201 return NO;
202
203success:
204 *anObject = date;
205 if (error != NULL) *error = nil;
206 return YES;
207}
208
209#pragma mark miscellaneous
210
211+ (BOOL)naturalLanguageParsingAvailable;
212{
213 return (my_perl != NULL);
214}
215@end
Note: See TracBrowser for help on using the repository browser.