p4ruby 2015.2.1265122-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : p4result.h
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : C++ class for holding results of Perforce commands
34
+ *
35
+ ******************************************************************************/
36
+
37
+ class P4Result
38
+ {
39
+ public:
40
+
41
+ P4Result();
42
+
43
+ // Setting
44
+ void AddOutput( VALUE v );
45
+ void AddMessage( Error *e );
46
+ void AddTrack( const char *msg );
47
+ void AddTrack( VALUE t );
48
+ void DeleteTrack();
49
+
50
+ // Getting
51
+ VALUE GetOutput() { return output; }
52
+ VALUE GetErrors() { return errors; }
53
+ VALUE GetWarnings() { return warnings; }
54
+ VALUE GetMessages() { return messages; }
55
+ VALUE GetTrack() { return track; }
56
+
57
+ // Get errors/warnings as a formatted string
58
+ void FmtErrors( StrBuf &buf );
59
+ void FmtWarnings( StrBuf &buf );
60
+
61
+ // Set API level for backwards compatibility
62
+ void SetApiLevel( int l ) { apiLevel = l; }
63
+ // Testing
64
+ int ErrorCount();
65
+ int WarningCount();
66
+
67
+ // Clear previous results
68
+ void Reset();
69
+
70
+ // Ruby garbage collection
71
+ void GCMark();
72
+
73
+ private:
74
+ int Length( VALUE ary );
75
+ void Fmt( const char *label, VALUE ary, StrBuf &buf );
76
+ VALUE FmtMessage( Error *e );
77
+ VALUE WrapMessage( Error *e );
78
+
79
+ VALUE cP4Msg;
80
+ VALUE output;
81
+ VALUE warnings;
82
+ VALUE errors;
83
+ VALUE messages;
84
+ VALUE track;
85
+ int apiLevel;
86
+ };
@@ -0,0 +1,46 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : p4rubydebug.h
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Debugging support for P4Ruby
34
+ *
35
+ ******************************************************************************/
36
+ #ifndef P4RUBYDEBUG_H
37
+ # define P4RUBYDEBUG_H
38
+
39
+ #define P4RDB_COMMANDS ( debug > 0 )
40
+ #define P4RDB_CALLS ( debug > 1 )
41
+ #define P4RDB_DATA ( debug > 2 )
42
+ #define P4RDB_GC ( debug > 3 )
43
+ #define P4RDB_RPC ( debug > 8 )
44
+ #define P4RDB_SSL ( debug > 10 )
45
+
46
+ #endif
@@ -0,0 +1,108 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2009, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : p4specdata.cpp
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Ruby bindings for the Perforce API. SpecData subclass for
34
+ * P4Ruby. This class allows for manipulation of Spec data
35
+ * stored in a Ruby hash using the standard Perforce classes
36
+ *
37
+ ******************************************************************************/
38
+
39
+ #include <ruby.h>
40
+ #include "undefdups.h"
41
+ #include <p4/clientapi.h>
42
+ #include <p4/i18napi.h>
43
+ #include <p4/spec.h>
44
+ #include <p4/debug.h>
45
+ #include "p4rubydebug.h"
46
+ #include "p4utils.h"
47
+ #include "p4specdata.h"
48
+
49
+ StrPtr *
50
+ SpecDataRuby::GetLine( SpecElem *sd, int x, const char **cmt )
51
+ {
52
+ *cmt = 0;
53
+ VALUE val;
54
+ VALUE key;
55
+ StrBuf t;
56
+
57
+ key = P4Utils::ruby_string( sd->tag.Text(), sd->tag.Length() );
58
+ val = rb_hash_aref( hash, key );
59
+ if( val == Qnil ) return 0;
60
+
61
+ if( !sd->IsList() )
62
+ {
63
+ last = StringValuePtr( val );
64
+ return &last;
65
+ }
66
+
67
+ // It's a list, which means we should have an array value here
68
+
69
+ if( !rb_obj_is_kind_of( val, rb_cArray ) )
70
+ {
71
+ rb_warn( "%s should be an array element. Ignoring...",
72
+ sd->tag.Text() );
73
+ return 0;
74
+ }
75
+ val = rb_ary_entry( val, x );
76
+ if( val == Qnil ) return 0;
77
+
78
+ last = StringValuePtr( val );
79
+ return &last;
80
+ }
81
+
82
+ void
83
+ SpecDataRuby::SetLine( SpecElem *sd, int x, const StrPtr *v, Error *e )
84
+ {
85
+ VALUE key;
86
+ VALUE val;
87
+ VALUE ary;
88
+ StrBuf t;
89
+
90
+ key = P4Utils::ruby_string( sd->tag.Text(), sd->tag.Length() );
91
+ val = P4Utils::ruby_string( v->Text(), v->Length() );
92
+
93
+ if( sd->IsList() )
94
+ {
95
+ ary = rb_hash_aref( hash, key );
96
+ if( ary == Qnil )
97
+ {
98
+ ary = rb_ary_new();
99
+ rb_hash_aset( hash, key, ary );
100
+ }
101
+ rb_ary_store( ary, x, val );
102
+ }
103
+ else
104
+ {
105
+ rb_hash_aset( hash, key, val );
106
+ }
107
+ return;
108
+ }
@@ -0,0 +1,52 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2009, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : p4specdata.h
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Ruby bindings for the Perforce API. SpecData subclass for
34
+ * P4Ruby. This class allows for manipulation of Spec data
35
+ * stored in a Ruby hash using the standard Perforce classes
36
+ *
37
+ ******************************************************************************/
38
+
39
+ class SpecDataRuby : public SpecData
40
+ {
41
+ public:
42
+ SpecDataRuby( VALUE h ) { hash = h; }
43
+
44
+ virtual StrPtr *GetLine( SpecElem *sd, int x, const char **cmt );
45
+ virtual void SetLine( SpecElem *sd, int x, const StrPtr *val,
46
+ Error *e );
47
+
48
+ private:
49
+ VALUE hash;
50
+ StrBuf last;
51
+ };
52
+
@@ -0,0 +1,62 @@
1
+ // vim:ts=8:sw=4:
2
+ /*******************************************************************************
3
+
4
+ Copyright (c) 2011, Perforce Software, Inc. All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
20
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ *******************************************************************************/
28
+ #include <ruby.h>
29
+ #ifdef HAVE_RUBY_ENCODING_H
30
+ #include <ruby/encoding.h>
31
+ #endif
32
+ #include "p4utils.h"
33
+
34
+ char *P4Utils::charset = 0;
35
+
36
+ VALUE P4Utils::ruby_string( const char *msg, long len )
37
+ {
38
+ VALUE str;
39
+ // If a length has been passed then use it
40
+ if( len )
41
+ {
42
+ str = rb_str_new( msg, len );
43
+ }
44
+ else
45
+ {
46
+ str = rb_str_new2( msg );
47
+ }
48
+
49
+ // Now check if an encoding should be set for the string.
50
+ #ifdef HAVE_RUBY_ENCODING_H
51
+ if( charset )
52
+ {
53
+ rb_enc_associate(str, rb_enc_find("UTF-8"));
54
+ }
55
+ else
56
+ {
57
+ rb_enc_associate(str, rb_locale_encoding());
58
+ }
59
+ #endif
60
+
61
+ return str;
62
+ }
@@ -0,0 +1,46 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2011, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : p4utils.h
30
+ *
31
+ * Author : Jayesh Mistry <jmistry@perforce.com>
32
+ *
33
+ * Description : C++ class with useful methods
34
+ *
35
+ ******************************************************************************/
36
+ class P4Utils {
37
+ public:
38
+ static void SetCharset( const char *cs ) { charset = (char *) cs; };
39
+ static char* GetCharset() { return charset; };
40
+
41
+ static VALUE ruby_string( const char *msg, long len = 0);
42
+
43
+ private:
44
+ static char* charset;
45
+ };
46
+
@@ -0,0 +1,721 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2007-2011, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : specmgr.cc
30
+ *
31
+ * Description : Ruby bindings for the Perforce API. Class for handling
32
+ * Perforce specs. This class provides other classes with
33
+ * generic support for parsing and formatting Perforce
34
+ * specs.
35
+ *
36
+ ******************************************************************************/
37
+ #include <ctype.h>
38
+ #include <ruby.h>
39
+ #include "p4utils.h"
40
+ #include "undefdups.h"
41
+ #include <p4/clientapi.h>
42
+ #include <p4/strops.h>
43
+ #include <p4/spec.h>
44
+ #include <p4/strtable.h>
45
+ #include "p4rubyconf.h"
46
+ #include "gc_hack.h"
47
+ #include "p4rubydebug.h"
48
+ #include "p4specdata.h"
49
+ #include "specmgr.h"
50
+
51
+ struct defaultspec {
52
+ const char *type;
53
+ const char *spec;
54
+ } speclist[] = {
55
+ {
56
+ "branch",
57
+ "Branch;code:301;rq;ro;fmt:L;len:32;;"
58
+ "Update;code:302;type:date;ro;fmt:L;len:20;;"
59
+ "Access;code:303;type:date;ro;fmt:L;len:20;;"
60
+ "Owner;code:304;fmt:R;len:32;;"
61
+ "Description;code:306;type:text;len:128;;"
62
+ "Options;code:309;type:line;len:32;val:"
63
+ "unlocked/locked;;"
64
+ "View;code:311;type:wlist;words:2;len:64;;"
65
+ },
66
+ {
67
+ "changeX",
68
+ "Change;code:201;rq;ro;fmt:L;seq:1;len:10;;"
69
+ "Date;code:202;type:date;ro;fmt:R;seq:3;len:20;;"
70
+ "Client;code:203;ro;fmt:L;seq:2;len:32;;"
71
+ "User;code:204;ro;fmt:L;seq:4;len:32;;"
72
+ "Status;code:205;ro;fmt:R;seq:5;len:10;;"
73
+ "Type;code:211;seq:6;type:select;fmt:L;len:10;"
74
+ "val:public/restricted;;"
75
+ "ImportedBy;code:212;type:line;ro;fmt:L;len:32;;"
76
+ "Identity;code:213;type:line;;"
77
+ "Description;code:206;type:text;rq;;"
78
+ "Jobs;code:209;type:wlist;words:2;len:32;;"
79
+ "Files;code:210;type:llist;len:64;;"
80
+ },
81
+ {
82
+ "change",
83
+ "Change;code:201;rq;ro;fmt:L;seq:1;len:10;;"
84
+ "Date;code:202;type:date;ro;fmt:R;seq:3;len:20;;"
85
+ "Client;code:203;ro;fmt:L;seq:2;len:32;;"
86
+ "User;code:204;ro;fmt:L;seq:4;len:32;;"
87
+ "Status;code:205;ro;fmt:R;seq:5;len:10;;"
88
+ "Type;code:211;seq:6;type:select;fmt:L;len:10;"
89
+ "val:public/restricted;;"
90
+ "ImportedBy;code:212;type:line;ro;fmt:L;len:32;;"
91
+ "Identity;code:213;type:line;;"
92
+ "Description;code:206;type:text;rq;seq:7;;"
93
+ "JobStatus;code:207;fmt:I;type:select;seq:9;;"
94
+ "Jobs;code:208;type:wlist;seq:8;len:32;;"
95
+ "Files;code:210;type:llist;len:64;;"
96
+ },
97
+ {
98
+ "client",
99
+ "Client;code:301;rq;ro;seq:1;len:32;;"
100
+ "Update;code:302;type:date;ro;seq:2;fmt:L;len:20;;"
101
+ "Access;code:303;type:date;ro;seq:4;fmt:L;len:20;;"
102
+ "Owner;code:304;seq:3;fmt:R;len:32;;"
103
+ "Host;code:305;seq:5;fmt:R;len:32;;"
104
+ "Description;code:306;type:text;len:128;;"
105
+ "Root;code:307;rq;type:line;len:64;;"
106
+ "AltRoots;code:308;type:llist;len:64;;"
107
+ "Options;code:309;type:line;len:64;val:"
108
+ "noallwrite/allwrite,noclobber/clobber,nocompress/compress,"
109
+ "unlocked/locked,nomodtime/modtime,normdir/rmdir;;"
110
+ "SubmitOptions;code:313;type:select;fmt:L;len:25;val:"
111
+ "submitunchanged/submitunchanged+reopen/revertunchanged/"
112
+ "revertunchanged+reopen/leaveunchanged/leaveunchanged+reopen;;"
113
+ "LineEnd;code:310;type:select;fmt:L;len:12;val:"
114
+ "local/unix/mac/win/share;;"
115
+ "Stream;code:314;type:line;len:64;;"
116
+ "StreamAtChange;code:316;type:line;len:64;;"
117
+ "ServerID;code:315;type:line;ro;len:64;;"
118
+ "Type;code:318;type:select;len:10;val:writeable/readonly;;"
119
+ "Backup;code:319;type:select;len:10;val:enable/disable;;"
120
+ "View;code:311;type:wlist;words:2;len:64;;"
121
+ "ChangeView;code:317;type:llist;len:64;;"
122
+ },
123
+ {
124
+ "clientX",
125
+ "Client;code:301;rq;ro;seq:1;len:32;;"
126
+ "Update;code:302;type:date;ro;seq:2;fmt:L;len:20;;"
127
+ "Access;code:303;type:date;ro;seq:4;fmt:L;len:20;;"
128
+ "Owner;code:304;seq:3;fmt:R;len:32;;"
129
+ "Host;code:305;seq:5;fmt:R;len:32;;"
130
+ "Description;code:306;type:text;len:128;;"
131
+ "Root;code:307;rq;type:line;len:64;;"
132
+ "AltRoots;code:308;type:llist;len:64;;"
133
+ "Options;code:309;type:line;len:64;val:"
134
+ "noallwrite/allwrite,noclobber/clobber,nocompress/compress,"
135
+ "unlocked/locked,nomodtime/modtime,normdir/rmdir;;"
136
+ "SubmitOptions;code:313;type:select;fmt:L;len:25;val:"
137
+ "submitunchanged/submitunchanged+reopen/revertunchanged/"
138
+ "revertunchanged+reopen/leaveunchanged/leaveunchanged+reopen;;"
139
+ "LineEnd;code:310;type:select;fmt:L;len:12;val:"
140
+ "local/unix/mac/win/share;;"
141
+ "View;code:311;type:wlist;words:2;len:64;;"
142
+ },
143
+ {
144
+ "clientSpecing021",
145
+ "Client;code:301;rq;ro;len:32;;"
146
+ "Update;code:302;type:date;ro;len:20;;"
147
+ "Access;code:303;type:date;ro;len:20;;"
148
+ "Owner;code:304;len:32;;"
149
+ "Host;code:305;len:32;;"
150
+ "Description;code:306;type:text;len:128;;"
151
+ "Root;code:307;rq;type:line;len:64;;"
152
+ "AltRoots;code:308;type:text;len:64;;"
153
+ "Options;code:309;type:line;len:64;val:"
154
+ "noallwrite/allwrite,noclobber/clobber,nocompress/compress,"
155
+ "unlocked/locked,nomodtime/modtime,normdir/rmdir;;"
156
+ "LineEnd;code:310;type:select;len:12;val:local/unix/mac/win/share;;"
157
+ "View;code:311;type:wlist;words:2;len:64;;"
158
+ },
159
+ {
160
+ "depot",
161
+ "Depot;code:251;rq;ro;len:32;;"
162
+ "Owner;code:252;len:32;;"
163
+ "Date;code:253;type:date;ro;len:20;;"
164
+ "Description;code:254;type:text;len:128;;"
165
+ "Type;code:255;rq;len:10;;"
166
+ "Address;code:256;len:64;;"
167
+ "Suffix;code:258;len:64;;"
168
+ "StreamDepth;code:260;len:64;;"
169
+ "Map;code:257;rq;len:64;;"
170
+ "SpecMap;code:259;type:wlist;len:64;;"
171
+ },
172
+ {
173
+ "group",
174
+ "Group;code:401;rq;ro;len:32;;"
175
+ "MaxResults;code:402;type:word;len:12;;"
176
+ "MaxScanRows;code:403;type:word;len:12;;"
177
+ "MaxLockTime;code:407;type:word;len:12;;"
178
+ "Timeout;code:406;type:word;len:12;;"
179
+ "PasswordTimeout;code:409;type:word;len:12;;"
180
+ "LdapConfig;code:410;type:line;len:128;;"
181
+ "LdapSearchQuery;code:411;type:line;len:128;;"
182
+ "LdapUserAttribute;code:412;type:line;len:128;;"
183
+ "Subgroups;code:404;type:wlist;len:32;opt:default;;"
184
+ "Owners;code:408;type:wlist;len:32;opt:default;;"
185
+ "Users;code:405;type:wlist;len:32;opt:default;;"
186
+ },
187
+ {
188
+ "job",
189
+ "Job;code:101;rq;len:32;;"
190
+ "Status;code:102;type:select;rq;len:10;"
191
+ "pre:open;val:open/suspended/closed;;"
192
+ "User;code:103;rq;len:32;pre:$user;;"
193
+ "Date;code:104;type:date;ro;len:20;pre:$now;;"
194
+ "Description;code:105;type:text;rq;pre:$blank;;"
195
+ },
196
+ {
197
+ "label",
198
+ "Label;code:301;rq;ro;fmt:L;len:32;;"
199
+ "Update;code:302;type:date;ro;fmt:L;len:20;;"
200
+ "Access;code:303;type:date;ro;fmt:L;len:20;;"
201
+ "Owner;code:304;fmt:R;len:32;;"
202
+ "Description;code:306;type:text;len:128;;"
203
+ "Options;code:309;type:line;len:64;val:"
204
+ "unlocked/locked,noautoreload/autoreload;;"
205
+ "Revision;code:312;type:word;words:1;len:64;;"
206
+ "ServerID;code:315;type:line;ro;len:64;;"
207
+ "View;code:311;type:wlist;len:64;;"
208
+ },
209
+ {
210
+ "ldap",
211
+ "Name;code:801;rq;len:32;;"
212
+ "Host;code:802;rq;type:word;words:1;len:128;;"
213
+ "Port;code:803;rq;type:word;words:1;len:5;;"
214
+ "Encryption;code:804;rq;len:10;val:"
215
+ "none/ssl/tls;;"
216
+ "BindMethod;code:805;rq;len:10;val:"
217
+ "simple/search/sasl;;"
218
+ "Options;code:816;type:line;len:64;val:"
219
+ "nodowncase/downcase,nogetattrs/getattrs,"
220
+ "norealminusername/realminusername;;"
221
+ "SimplePattern;code:806;type:line;len:128;;"
222
+ "SearchBaseDN;code:807;type:line;len:128;;"
223
+ "SearchFilter;code:808;type:line;len:128;;"
224
+ "SearchScope;code:809;len:10;val:"
225
+ "baseonly/children/subtree;;"
226
+ "SearchBindDN;code:810;type:line;len:128;;"
227
+ "SearchPasswd;code:811;type:line;len:128;;"
228
+ "SaslRealm;code:812;type:word;words:1;len:128;;"
229
+ "GroupBaseDN;code:813;type:line;len:128;;"
230
+ "GroupSearchFilter;code:814;type:line;len:128;;"
231
+ "GroupSearchScope;code:815;len:10;val:"
232
+ "baseonly/children/subtree;;"
233
+ "AttributeUid;code:817;type:word;len:128;;"
234
+ "AttributeName;code:818;type:line;len:128;;"
235
+ "AttributeEmail;code:819;type:word;len:128;;"
236
+ },
237
+ {
238
+ "license",
239
+ "License;code:451;len:32;;"
240
+ "License-Expires;code:452;len:10;;"
241
+ "Support-Expires;code:453;len:10;;"
242
+ "Customer;code:454;type:line;len:128;;"
243
+ "Application;code:455;len:32;;"
244
+ "IPaddress;code:456;len:24;;"
245
+ "IPservice;code:461;type:wlist;len:24;;"
246
+ "Platform;code:457;len:32;;"
247
+ "Clients;code:458;len:8;;"
248
+ "Users;code:459;len:8;;"
249
+ "Files;code:460;len:8;;"
250
+ },
251
+ {
252
+ "protect",
253
+ "Protections;code:501;fmt:C;type:wlist;words:5;opt:default;len:64;;"
254
+ },
255
+ {
256
+ "remote",
257
+ "RemoteID;code:851;rq;ro;len:32;;"
258
+ "Address;code:852;rq;type:line;len:32;;"
259
+ "Owner;code:853;fmt:R;len:32;;"
260
+ "RemoteUser;code:861;fmt:R;len:32;;"
261
+ "Options;code:854;type:line;len:32;val:"
262
+ "unlocked/lockednocompress/compress;;"
263
+ "Update;code:855;type:date;ro;fmt:L;len:20;;"
264
+ "Access;code:856;type:date;ro;fmt:L;len:20;;"
265
+ "Description;code:857;type:text;len:128;;"
266
+ "LastFetch;code:858;fmt:L;len:10;;"
267
+ "LastPush;code:859;fmt:L;len:10;;"
268
+ "DepotMap;code:860;type:wlist;words:2;len:64;;"
269
+ },
270
+ {
271
+ "specW",
272
+ "Fields;code:351;type:wlist;words:5;rq;;"
273
+ "Required;code:357;type:wlist;;"
274
+ "Readonly;code:358;type:wlist;;"
275
+ "Words;code:352;type:wlist;words:2;;"
276
+ "Formats;code:353;type:wlist;words:3;;"
277
+ "Values;code:354;type:wlist;words:2;;"
278
+ "Presets;code:355;type:wlist;words:2;;"
279
+ "Comments;code:356;type:text;;"
280
+ },
281
+ {
282
+ "spec",
283
+ "Fields;code:351;type:wlist;words:5;rq;;"
284
+ "Words;code:352;type:wlist;words:2;;"
285
+ "Formats;code:353;type:wlist;words:3;;"
286
+ "Values;code:354;type:wlist;words:2;;"
287
+ "Presets;code:355;type:wlist;words:2;;"
288
+ "Openable;code:362;type:wlist;words:2;;"
289
+ "Comments;code:356;type:text;;"
290
+ },
291
+ {
292
+ "stream",
293
+ "Stream;code:701;rq;ro;len:64;;"
294
+ "Update;code:705;type:date;ro;fmt:L;len:20;;"
295
+ "Access;code:706;type:date;ro;fmt:L;len:20;;"
296
+ "Owner;code:704;len:32;;"
297
+ "Name;code:703;rq;type:line;len:32;;"
298
+ "Parent;code:702;rq;len:64;open:isolate;;"
299
+ "Type;code:708;rq;len:32;open:isolate;;"
300
+ "Description;code:709;type:text;len:128;;"
301
+ "Options;code:707;type:line;len:64;val:"
302
+ "allsubmit/ownersubmit,unlocked/locked,"
303
+ "toparent/notoparent,fromparent/nofromparent,"
304
+ "mergedown/mergeany;;"
305
+ "Paths;code:710;rq;type:wlist;words:2;maxwords:3;len:64;open:isolate;;"
306
+ "Remapped;code:711;type:wlist;words:2;len:64;open:isolate;;"
307
+ "Ignored;code:712;type:wlist;words:1;len:64;open:isolate;;"
308
+ "View;code:713;type:wlist;words:2;len:64;;"
309
+ "ChangeView;code:714;type:llist;ro;len:64;;"
310
+ },
311
+ {
312
+ "triggers",
313
+ "Triggers;code:551;type:wlist;words:4;len:64;opt:default;"
314
+ },
315
+ {
316
+ "typemap",
317
+ "TypeMap;code:601;type:wlist;words:2;len:64;opt:default;"
318
+ },
319
+ {
320
+ "user",
321
+ "User;code:651;rq;ro;seq:1;len:32;;"
322
+ "Type;code:659;ro;fmt:R;len:10;;"
323
+ "Email;code:652;fmt:R;rq;seq:3;len:32;;"
324
+ "Update;code:653;fmt:L;type:date;ro;seq:2;len:20;;"
325
+ "Access;code:654;fmt:L;type:date;ro;len:20;;"
326
+ "FullName;code:655;fmt:R;type:line;rq;len:32;;"
327
+ "JobView;code:656;type:line;len:64;;"
328
+ "Password;code:657;len:32;;"
329
+ "AuthMethod;code:662;fmt:L;len:10;val:perforce/ldap;;"
330
+ "Reviews;code:658;type:wlist;len:64;;"
331
+ },
332
+ {
333
+ "server",
334
+ "ServerID;code:751;rq;ro;len:32;;"
335
+ "Type;code:752;rq;len:32;;"
336
+ "Name;code:753;type:line;len:32;;"
337
+ "Address;code:754;type:line;len:32;;"
338
+ "ExternalAddress;code:755;type:line;len:32;;"
339
+ "Services;code:756;rq;len:128;;"
340
+ "Description;code:757;type:text;len:128;;"
341
+ "User;code:761;type:line;len:64;;"
342
+ "ClientDataFilter;code:758;type:wlist;len:64;;"
343
+ "RevisionDataFilter;code:759;type:wlist;len:64;;"
344
+ "ArchiveDataFilter;code:760;type:wlist;len:64;;"
345
+ },
346
+ { 0, 0 }
347
+ };
348
+
349
+ SpecMgr::SpecMgr()
350
+ {
351
+ debug = 0;
352
+ specs = 0;
353
+ Reset();
354
+ }
355
+
356
+ SpecMgr::~SpecMgr()
357
+ {
358
+ delete specs;
359
+ }
360
+
361
+ void
362
+ SpecMgr::AddSpecDef( const char *type, StrPtr &specDef )
363
+ {
364
+ if( specs->GetVar( type ) )
365
+ specs->RemoveVar( type );
366
+ specs->SetVar( type, specDef );
367
+ }
368
+
369
+ void
370
+ SpecMgr::AddSpecDef( const char *type, const char *specDef )
371
+ {
372
+ if( specs->GetVar( type ) )
373
+ specs->RemoveVar( type );
374
+ specs->SetVar( type, specDef );
375
+ }
376
+
377
+
378
+ void
379
+ SpecMgr::Reset()
380
+ {
381
+ delete specs;
382
+ specs = new StrBufDict;
383
+
384
+ for( struct defaultspec *sp = &speclist[ 0 ]; sp->type; sp++ )
385
+ AddSpecDef( sp->type, sp->spec );
386
+
387
+ }
388
+
389
+ int
390
+ SpecMgr::HaveSpecDef( const char *type )
391
+ {
392
+ return specs->GetVar( type ) != 0;
393
+ }
394
+
395
+ //
396
+ // Convert a Perforce StrDict into a Ruby hash. Convert multi-level
397
+ // data (Files0, Files1 etc. ) into (nested) array members of the hash.
398
+ //
399
+
400
+ VALUE
401
+ SpecMgr::StrDictToHash( StrDict *dict, VALUE hash )
402
+ {
403
+ StrRef var, val;
404
+ int i;
405
+
406
+ if( hash == Qnil )
407
+ hash = rb_hash_new();
408
+
409
+ for ( i = 0; dict->GetVar( i, var, val ); i++ )
410
+ {
411
+ if ( var == "specdef" || var == "func" || var == "specFormatted" )
412
+ continue;
413
+
414
+ InsertItem( hash, &var, &val );
415
+ }
416
+ return hash;
417
+ }
418
+
419
+ //
420
+ // Convert a Perforce StrDict into a P4::Spec object
421
+ //
422
+
423
+ VALUE
424
+ SpecMgr::StrDictToSpec( StrDict *dict, StrPtr *specDef )
425
+ {
426
+
427
+ // This converts it to a string, and then to a hash, so we go from one
428
+ // type of dictionary to another, via an intermediate form (a StrBuf).
429
+
430
+ Error e;
431
+ SpecDataTable dictData( dict );
432
+ #if P4APIVER_ID >= 513538
433
+ Spec s( specDef->Text(), "", &e );
434
+ #else
435
+ Spec s( specDef->Text(), "" );
436
+ #endif
437
+ StrBuf form;
438
+
439
+ if( e.Test() ) return Qfalse;
440
+
441
+ // Format the StrDict into a StrBuf object
442
+ s.Format( &dictData, &form );
443
+
444
+ // Now parse the StrBuf into a new P4::Spec object
445
+ VALUE spec = NewSpec( specDef );
446
+ SpecDataRuby hashData( spec );
447
+
448
+ s.ParseNoValid( form.Text(), &hashData, &e );
449
+ if( e.Test() ) return Qfalse;
450
+
451
+ // Now see if there are any extraTag fields as we'll need to
452
+ // add those fields into our output. Just iterate over them
453
+ // extracting the fields and inserting them as we go.
454
+ int i = 0;
455
+ StrRef et("extraTag" );
456
+ for( i = 0; ; i++ )
457
+ {
458
+ StrBuf tag;
459
+ StrPtr *var;
460
+ StrPtr *val;
461
+
462
+ tag << et << i;
463
+ if( !(var = dict->GetVar( tag ) ) )
464
+ break;
465
+
466
+ val = dict->GetVar( *var );
467
+ if( !val ) continue;
468
+
469
+ InsertItem( spec, var, val );
470
+ }
471
+
472
+ return spec;
473
+ }
474
+
475
+ VALUE
476
+ SpecMgr::StringToSpec( const char *type, const char *form, Error *e )
477
+ {
478
+
479
+ StrPtr * specDef = specs->GetVar( type );
480
+ VALUE hash = NewSpec( specDef );
481
+ SpecDataRuby specData( hash );
482
+ #if P4APIVER_ID >= 513538
483
+ Spec s( specDef->Text(), "", e );
484
+ #else
485
+ Spec s( specDef->Text(), "" );
486
+ #endif
487
+
488
+ if( !e->Test() )
489
+ s.ParseNoValid( form, &specData, e );
490
+
491
+ if ( e->Test() )
492
+ return Qfalse;
493
+
494
+ return hash;
495
+ }
496
+
497
+
498
+ //
499
+ // Format routine. updates a StrBuf object with the form content.
500
+ // The StrBuf can then be converted to a Ruby string where required.
501
+ //
502
+ void
503
+ SpecMgr::SpecToString( const char *type, VALUE hash, StrBuf &b, Error *e )
504
+ {
505
+
506
+ StrBuf buf;
507
+ StrPtr * specDef = specs->GetVar( type );
508
+ if ( !specDef )
509
+ {
510
+ e->Set( E_FAILED, "No specdef available. Cannot convert hash to a "
511
+ "Perforce form" );
512
+ return;
513
+ }
514
+
515
+ SpecDataRuby specData( hash );
516
+ #if P4APIVER_ID >= 513538
517
+ Spec s( specDef->Text(), "", e );
518
+ #else
519
+ Spec s( specDef->Text(), "" );
520
+ #endif
521
+
522
+ if( e->Test() ) return;
523
+
524
+ s.Format( &specData, &b );
525
+ }
526
+
527
+ //
528
+ // This method returns a hash describing the valid fields in the spec. To
529
+ // make it easy on our users, we map the lowercase name to the name defined
530
+ // in the spec. Thus, the users can always user lowercase, and if the field
531
+ // should be in mixed case, it will be. See P4::Spec::method_missing
532
+ //
533
+
534
+ VALUE
535
+ SpecMgr::SpecFields( const char *type )
536
+ {
537
+ return SpecFields( specs->GetVar( type ) );
538
+ }
539
+
540
+ VALUE
541
+ SpecMgr::SpecFields( StrPtr *specDef )
542
+ {
543
+ if( !specDef ) return Qnil;
544
+
545
+ //
546
+ // Here we abuse the fact that SpecElem::tag is public, even though it's
547
+ // only supposed to be public to SpecData's subclasses. It's hard to
548
+ // see that changing anytime soon, and it makes this so simple and
549
+ // reliable. So...
550
+ //
551
+ VALUE hash = rb_hash_new();
552
+ Error e;
553
+
554
+ #if P4APIVER_ID >= 513538
555
+ Spec s( specDef->Text(), "", &e );
556
+ #else
557
+ Spec s( specDef->Text(), "" );
558
+ #endif
559
+ if( e.Test() ) return Qnil;
560
+
561
+ for( int i = 0; i < s.Count(); i++ )
562
+ {
563
+ StrBuf k;
564
+ StrBuf v;
565
+ SpecElem * se = s.Get( i );
566
+
567
+ v = se->tag;
568
+ k = v;
569
+ StrOps::Lower( k );
570
+
571
+ rb_hash_aset(hash,
572
+ P4Utils::ruby_string( k.Text(), k.Length() ),
573
+ P4Utils::ruby_string( v.Text(), v.Length() ) );
574
+ }
575
+ return hash;
576
+ }
577
+
578
+ //
579
+ // Split a key into its base name and its index. i.e. for a key "how1,0"
580
+ // the base name is "how" and they index is "1,0". We work backwards from
581
+ // the end of the key looking for the first char that is neither a
582
+ // digit, nor a comma.
583
+ //
584
+
585
+ void
586
+ SpecMgr::SplitKey( const StrPtr *key, StrBuf &base, StrBuf &index )
587
+ {
588
+ int i = 0;
589
+
590
+ base = *key;
591
+ index = "";
592
+ for ( i = key->Length(); i; i-- )
593
+ {
594
+ char prev = (*key)[ i-1 ];
595
+ if ( !isdigit( prev ) && prev != ',' )
596
+ {
597
+ base.Set( key->Text(), i );
598
+ index.Set( key->Text() + i );
599
+ break;
600
+ }
601
+ }
602
+ }
603
+
604
+ //
605
+ // Insert an element into the response structure. The element may need to
606
+ // be inserted into an array nested deeply within the enclosing hash.
607
+ //
608
+
609
+ void
610
+ SpecMgr::InsertItem( VALUE hash, const StrPtr *var, const StrPtr *val )
611
+ {
612
+ VALUE ary = 0;
613
+ VALUE tary = 0;
614
+ VALUE key;
615
+ ID idLength = rb_intern( "length" );
616
+ StrBuf base, index;
617
+ StrRef comma( "," );
618
+
619
+ SplitKey( var, base, index );
620
+
621
+ // If there's no index, then we insert into the top level hash
622
+ // but if the key is already defined then we need to rename the key. This
623
+ // is probably one of those special keys like otherOpen which can be
624
+ // both an array element and a scalar. The scalar comes last, so we
625
+ // just rename it to "otherOpens" to avoid trashing the previous key
626
+ // value
627
+ if ( index == "" )
628
+ {
629
+ ID idHasKey = rb_intern( "has_key?");
630
+ ID idPlus = rb_intern( "+" );
631
+
632
+ key = P4Utils::ruby_string( var->Text() );
633
+ if ( rb_funcall( hash, idHasKey, 1, key ) == Qtrue )
634
+ key = rb_funcall( key, idPlus, 1, P4Utils::ruby_string( "s" ) );
635
+
636
+ if( P4RDB_DATA )
637
+ fprintf( stderr, "... %s -> %s\n", StringValuePtr( key ), val->Text() );
638
+
639
+ rb_hash_aset( hash, key, P4Utils::ruby_string( val->Text() ) );
640
+ return;
641
+ }
642
+
643
+ //
644
+ // Get or create the parent array from the hash.
645
+ //
646
+ key = P4Utils::ruby_string( base.Text() );
647
+ ary = rb_hash_aref( hash, key );
648
+
649
+ if ( Qnil == ary )
650
+ {
651
+ ary = rb_ary_new();
652
+ rb_hash_aset( hash, key, ary );
653
+ }
654
+ else if( rb_obj_is_kind_of( ary, rb_cArray ) != Qtrue )
655
+ {
656
+ //
657
+ // There's an index in our var name, but the name is already defined
658
+ // and the value it contains is not an array. This means we've got a
659
+ // name collision. This can happen in 'p4 diff2' for example, when
660
+ // one file gets 'depotFile' and the other gets 'depotFile2'. In
661
+ // these cases it makes sense to keep the structure flat so we
662
+ // just use the raw variable name.
663
+ //
664
+ if( P4RDB_DATA )
665
+ fprintf( stderr, "... %s -> %s\n", var->Text(), val->Text() );
666
+
667
+ rb_hash_aset( hash, P4Utils::ruby_string( var->Text() ) ,
668
+ P4Utils::ruby_string( val->Text() ) );
669
+ return;
670
+ }
671
+
672
+ // The index may be a simple digit, or it could be a comma separated
673
+ // list of digits. For each "level" in the index, we need a containing
674
+ // array.
675
+ if( P4RDB_DATA )
676
+ fprintf( stderr, "... %s -> [", base.Text() );
677
+
678
+ for( const char *c = 0 ; ( c = index.Contains( comma ) ); )
679
+ {
680
+ StrBuf level;
681
+ level.Set( index.Text(), c - index.Text() );
682
+ index.Set( c + 1 );
683
+
684
+ // Found another level so we need to get/create a nested array
685
+ // under the current entry. We use the level as an index so that
686
+ // missing entries are left empty deliberately.
687
+
688
+ tary = rb_ary_entry( ary, level.Atoi() );
689
+ if ( ! RTEST( tary ) )
690
+ {
691
+ tary = rb_ary_new();
692
+ rb_ary_store( ary, level.Atoi(), tary );
693
+ }
694
+ if( P4RDB_DATA )
695
+ fprintf( stderr, "%s][", level.Text() );
696
+ ary = tary;
697
+ }
698
+ int pos = index.Atoi();
699
+
700
+ if( P4RDB_DATA )
701
+ fprintf( stderr, "%d] = %s\n", pos, val->Text() );
702
+
703
+ rb_ary_store( ary, pos, P4Utils::ruby_string( val->Text() ) );
704
+ }
705
+
706
+ //
707
+ // Create a new P4::Spec object and return it.
708
+ //
709
+
710
+ VALUE
711
+ SpecMgr::NewSpec( StrPtr *specDef )
712
+ {
713
+ ID idNew = rb_intern( "new" );
714
+ ID idP4 = rb_intern( "P4" );
715
+ ID idP4Spec = rb_intern( "Spec" );
716
+ VALUE cP4 = rb_const_get_at( rb_cObject, idP4 );
717
+ VALUE cP4Spec = rb_const_get_at( cP4, idP4Spec );
718
+ VALUE fields = SpecFields( specDef );
719
+
720
+ return rb_funcall( cP4Spec, idNew, 1, fields );
721
+ }