p4ruby 2014.1 → 2014.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/P4/p4result.h ADDED
@@ -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,45 @@
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
+
45
+ #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
+ }
data/ext/P4/p4utils.h ADDED
@@ -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,604 @@
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
+ {
57
+ "branch",
58
+ "Branch;code:301;rq;ro;fmt:L;len:32;;"
59
+ "Update;code:302;type:date;ro;fmt:L;len:20;;"
60
+ "Access;code:303;type:date;ro;fmt:L;len:20;;"
61
+ "Owner;code:304;fmt:R;len:32;;"
62
+ "Description;code:306;type:text;len:128;;"
63
+ "Options;code:309;type:line;len:32;val:"
64
+ "unlocked/locked;;"
65
+ "View;code:311;type:wlist;words:2;len:64;;"
66
+ },
67
+ {
68
+ "change",
69
+ "Change;code:201;rq;ro;fmt:L;seq:1;len:10;;"
70
+ "Date;code:202;type:date;ro;fmt:R;seq:3;len:20;;"
71
+ "Client;code:203;ro;fmt:L;seq:2;len:32;;"
72
+ "User;code:204;ro;fmt:L;seq:4;len:32;;"
73
+ "Status;code:205;ro;fmt:R;seq:5;len:10;;"
74
+ "Type;code:211;seq:6;type:select;fmt:L;len:10;"
75
+ "val:public/restricted;;"
76
+ "Description;code:206;type:text;rq;seq:7;;"
77
+ "JobStatus;code:207;fmt:I;type:select;seq:9;;"
78
+ "Jobs;code:208;type:wlist;seq:8;len:32;;"
79
+ "Files;code:210;type:llist;len:64;;"
80
+ },
81
+ {
82
+ "client",
83
+ "Client;code:301;rq;ro;seq:1;len:32;;"
84
+ "Update;code:302;type:date;ro;seq:2;fmt:L;len:20;;"
85
+ "Access;code:303;type:date;ro;seq:4;fmt:L;len:20;;"
86
+ "Owner;code:304;seq:3;fmt:R;len:32;;"
87
+ "Host;code:305;seq:5;fmt:R;len:32;;"
88
+ "Description;code:306;type:text;len:128;;"
89
+ "Root;code:307;rq;type:line;len:64;;"
90
+ "AltRoots;code:308;type:llist;len:64;;"
91
+ "Options;code:309;type:line;len:64;val:"
92
+ "noallwrite/allwrite,noclobber/clobber,nocompress/compress,"
93
+ "unlocked/locked,nomodtime/modtime,normdir/rmdir;;"
94
+ "SubmitOptions;code:313;type:select;fmt:L;len:25;val:"
95
+ "submitunchanged/submitunchanged+reopen/revertunchanged/"
96
+ "revertunchanged+reopen/leaveunchanged/leaveunchanged+reopen;;"
97
+ "LineEnd;code:310;type:select;fmt:L;len:12;val:"
98
+ "local/unix/mac/win/share;;"
99
+ "Stream;code:314;type:line;len:64;;"
100
+ "StreamAtChange;code:316;type:line;len:64;;"
101
+ "ServerID;code:315;type:line;ro;len:64;;"
102
+ "View;code:311;type:wlist;words:2;len:64;;"
103
+ "ChangeView;code:317;type:llist;ro;len:64;;"
104
+ },
105
+ {
106
+ "depot",
107
+ "Depot;code:251;rq;ro;len:32;;"
108
+ "Owner;code:252;len:32;;"
109
+ "Date;code:253;type:date;ro;len:20;;"
110
+ "Description;code:254;type:text;len:128;;"
111
+ "Type;code:255;rq;len:10;;"
112
+ "Address;code:256;len:64;;"
113
+ "Suffix;code:258;len:64;;"
114
+ "Map;code:257;rq;len:64;;"
115
+ "SpecMap;code:259;type:wlist;len:64;;"
116
+ },
117
+ {
118
+ "group",
119
+ "Group;code:401;rq;ro;len:32;;"
120
+ "MaxResults;code:402;type:word;len:12;;"
121
+ "MaxScanRows;code:403;type:word;len:12;;"
122
+ "MaxLockTime;code:407;type:word;len:12;;"
123
+ "Timeout;code:406;type:word;len:12;;"
124
+ "PasswordTimeout;code:409;type:word;len:12;;"
125
+ "Subgroups;code:404;type:wlist;len:32;opt:default;;"
126
+ "Owners;code:408;type:wlist;len:32;opt:default;;"
127
+ "Users;code:405;type:wlist;len:32;opt:default;;"
128
+ },
129
+ {
130
+ "job",
131
+ "Job;code:101;rq;len:32;;"
132
+ "Status;code:102;type:select;rq;len:10;"
133
+ "pre:open;val:open/suspended/closed;;"
134
+ "User;code:103;rq;len:32;pre:$user;;"
135
+ "Date;code:104;type:date;ro;len:20;pre:$now;;"
136
+ "Description;code:105;type:text;rq;pre:$blank;;"
137
+ },
138
+ {
139
+ "label",
140
+ "Label;code:301;rq;ro;fmt:L;len:32;;"
141
+ "Update;code:302;type:date;ro;fmt:L;len:20;;"
142
+ "Access;code:303;type:date;ro;fmt:L;len:20;;"
143
+ "Owner;code:304;fmt:R;len:32;;"
144
+ "Description;code:306;type:text;len:128;;"
145
+ "Options;code:309;type:line;len:64;val:"
146
+ "unlocked/locked,noautoreload/autoreload;;"
147
+ "Revision;code:312;type:word;words:1;len:64;;"
148
+ "ServerID;code:315;type:line;ro;len:64;;"
149
+ "View;code:311;type:wlist;len:64;;"
150
+ },
151
+ {
152
+ "license",
153
+ "License;code:451;len:32;;"
154
+ "License-Expires;code:452;len:10;;"
155
+ "Support-Expires;code:453;len:10;;"
156
+ "Customer;code:454;type:line;len:128;;"
157
+ "Application;code:455;len:32;;"
158
+ "IPaddress;code:456;len:24;;"
159
+ "IPservice;code:461;type:wlist;len:24;;"
160
+ "Platform;code:457;len:32;;"
161
+ "Clients;code:458;len:8;;"
162
+ "Users;code:459;len:8;;"
163
+ "Files;code:460;len:8;;"
164
+ },
165
+ {
166
+ "protect",
167
+ "Protections;code:501;type:wlist;words:5;opt:default;len:64;;"
168
+ },
169
+ {
170
+ "spec",
171
+ "Fields;code:351;type:wlist;words:5;rq;;"
172
+ "Words;code:352;type:wlist;words:2;;"
173
+ "Formats;code:353;type:wlist;words:3;;"
174
+ "Values;code:354;type:wlist;words:2;;"
175
+ "Presets;code:355;type:wlist;words:2;;"
176
+ "Comments;code:356;type:text;;"
177
+ },
178
+ {
179
+ "stream",
180
+ "Stream;code:701;rq;ro;len:64;;"
181
+ "Update;code:705;type:date;ro;fmt:L;len:20;;"
182
+ "Access;code:706;type:date;ro;fmt:L;len:20;;"
183
+ "Owner;code:704;len:32;;"
184
+ "Name;code:703;rq;type:line;len:32;;"
185
+ "Parent;code:702;rq;len:64;;"
186
+ "Type;code:708;rq;len:32;;"
187
+ "Description;code:709;type:text;len:128;;"
188
+ "Options;code:707;type:line;len:64;val:"
189
+ "allsubmit/ownersubmit,unlocked/locked,"
190
+ "toparent/notoparent,fromparent/nofromparent;;"
191
+ "Paths;code:710;rq;type:wlist;words:2;maxwords:3;len:64;;"
192
+ "Remapped;code:711;type:wlist;words:2;len:64;;"
193
+ "Ignored;code:712;type:wlist;words:1;len:64;;"
194
+ "View;code:713;type:wlist;words:2;len:64;;"
195
+ "ChangeView;code:714;type:llist;ro;len:64;;"
196
+ },
197
+ {
198
+ "triggers",
199
+ "Triggers;code:551;type:wlist;words:4;len:64;opt:default;"
200
+ },
201
+ {
202
+ "typemap",
203
+ "TypeMap;code:601;type:wlist;words:2;len:64;opt:default;"
204
+ },
205
+ {
206
+ "user",
207
+ "User;code:651;rq;ro;seq:1;len:32;;"
208
+ "Type;code:659;ro;fmt:R;len:10;;"
209
+ "Email;code:652;fmt:R;rq;seq:3;len:32;;"
210
+ "Update;code:653;fmt:L;type:date;ro;seq:2;len:20;;"
211
+ "Access;code:654;fmt:L;type:date;ro;len:20;;"
212
+ "FullName;code:655;fmt:R;type:line;rq;len:32;;"
213
+ "JobView;code:656;type:line;len:64;;"
214
+ "Password;code:657;len:32;;"
215
+ "Reviews;code:658;type:wlist;len:64;;"
216
+ },
217
+ {
218
+ "server",
219
+ "ServerID;code:751;rq;ro;len:32;;"
220
+ "Type;code:752;rq;len:32;;"
221
+ "Name;code:753;type:line;len:32;;"
222
+ "Address;code:754;type:line;len:32;;"
223
+ "Services;code:755;rq;len:128;;"
224
+ "Description;code:756;type:text;len:128;;"
225
+ "ClientDataFilter;code:757;type:wlist;len:64;;"
226
+ "RevisionDataFilter;code:758;type:wlist;len:64;;"
227
+ "ArchiveDataFilter;code:759;type:wlist;len:64;;"
228
+ },
229
+ { 0, 0 }
230
+ };
231
+
232
+ SpecMgr::SpecMgr()
233
+ {
234
+ debug = 0;
235
+ specs = 0;
236
+ Reset();
237
+ }
238
+
239
+ SpecMgr::~SpecMgr()
240
+ {
241
+ delete specs;
242
+ }
243
+
244
+ void
245
+ SpecMgr::AddSpecDef( const char *type, StrPtr &specDef )
246
+ {
247
+ if( specs->GetVar( type ) )
248
+ specs->RemoveVar( type );
249
+ specs->SetVar( type, specDef );
250
+ }
251
+
252
+ void
253
+ SpecMgr::AddSpecDef( const char *type, const char *specDef )
254
+ {
255
+ if( specs->GetVar( type ) )
256
+ specs->RemoveVar( type );
257
+ specs->SetVar( type, specDef );
258
+ }
259
+
260
+
261
+ void
262
+ SpecMgr::Reset()
263
+ {
264
+ delete specs;
265
+ specs = new StrBufDict;
266
+
267
+ for( struct defaultspec *sp = &speclist[ 0 ]; sp->type; sp++ )
268
+ AddSpecDef( sp->type, sp->spec );
269
+
270
+ }
271
+
272
+ int
273
+ SpecMgr::HaveSpecDef( const char *type )
274
+ {
275
+ return specs->GetVar( type ) != 0;
276
+ }
277
+
278
+ //
279
+ // Convert a Perforce StrDict into a Ruby hash. Convert multi-level
280
+ // data (Files0, Files1 etc. ) into (nested) array members of the hash.
281
+ //
282
+
283
+ VALUE
284
+ SpecMgr::StrDictToHash( StrDict *dict, VALUE hash )
285
+ {
286
+ StrRef var, val;
287
+ int i;
288
+
289
+ if( hash == Qnil )
290
+ hash = rb_hash_new();
291
+
292
+ for ( i = 0; dict->GetVar( i, var, val ); i++ )
293
+ {
294
+ if ( var == "specdef" || var == "func" || var == "specFormatted" )
295
+ continue;
296
+
297
+ InsertItem( hash, &var, &val );
298
+ }
299
+ return hash;
300
+ }
301
+
302
+ //
303
+ // Convert a Perforce StrDict into a P4::Spec object
304
+ //
305
+
306
+ VALUE
307
+ SpecMgr::StrDictToSpec( StrDict *dict, StrPtr *specDef )
308
+ {
309
+
310
+ // This converts it to a string, and then to a hash, so we go from one
311
+ // type of dictionary to another, via an intermediate form (a StrBuf).
312
+
313
+ Error e;
314
+ SpecDataTable dictData( dict );
315
+ #if P4APIVER_ID >= 513538
316
+ Spec s( specDef->Text(), "", &e );
317
+ #else
318
+ Spec s( specDef->Text(), "" );
319
+ #endif
320
+ StrBuf form;
321
+
322
+ if( e.Test() ) return Qfalse;
323
+
324
+ // Format the StrDict into a StrBuf object
325
+ s.Format( &dictData, &form );
326
+
327
+ // Now parse the StrBuf into a new P4::Spec object
328
+ VALUE spec = NewSpec( specDef );
329
+ SpecDataRuby hashData( spec );
330
+
331
+ s.ParseNoValid( form.Text(), &hashData, &e );
332
+ if( e.Test() ) return Qfalse;
333
+
334
+ // Now see if there are any extraTag fields as we'll need to
335
+ // add those fields into our output. Just iterate over them
336
+ // extracting the fields and inserting them as we go.
337
+ int i = 0;
338
+ StrRef et("extraTag" );
339
+ for( i = 0; ; i++ )
340
+ {
341
+ StrBuf tag;
342
+ StrPtr *var;
343
+ StrPtr *val;
344
+
345
+ tag << et << i;
346
+ if( !(var = dict->GetVar( tag ) ) )
347
+ break;
348
+
349
+ val = dict->GetVar( *var );
350
+ if( !val ) continue;
351
+
352
+ InsertItem( spec, var, val );
353
+ }
354
+
355
+ return spec;
356
+ }
357
+
358
+ VALUE
359
+ SpecMgr::StringToSpec( const char *type, const char *form, Error *e )
360
+ {
361
+
362
+ StrPtr * specDef = specs->GetVar( type );
363
+ VALUE hash = NewSpec( specDef );
364
+ SpecDataRuby specData( hash );
365
+ #if P4APIVER_ID >= 513538
366
+ Spec s( specDef->Text(), "", e );
367
+ #else
368
+ Spec s( specDef->Text(), "" );
369
+ #endif
370
+
371
+ if( !e->Test() )
372
+ s.ParseNoValid( form, &specData, e );
373
+
374
+ if ( e->Test() )
375
+ return Qfalse;
376
+
377
+ return hash;
378
+ }
379
+
380
+
381
+ //
382
+ // Format routine. updates a StrBuf object with the form content.
383
+ // The StrBuf can then be converted to a Ruby string where required.
384
+ //
385
+ void
386
+ SpecMgr::SpecToString( const char *type, VALUE hash, StrBuf &b, Error *e )
387
+ {
388
+
389
+ StrBuf buf;
390
+ StrPtr * specDef = specs->GetVar( type );
391
+ if ( !specDef )
392
+ {
393
+ e->Set( E_FAILED, "No specdef available. Cannot convert hash to a "
394
+ "Perforce form" );
395
+ return;
396
+ }
397
+
398
+ SpecDataRuby specData( hash );
399
+ #if P4APIVER_ID >= 513538
400
+ Spec s( specDef->Text(), "", e );
401
+ #else
402
+ Spec s( specDef->Text(), "" );
403
+ #endif
404
+
405
+ if( e->Test() ) return;
406
+
407
+ s.Format( &specData, &b );
408
+ }
409
+
410
+ //
411
+ // This method returns a hash describing the valid fields in the spec. To
412
+ // make it easy on our users, we map the lowercase name to the name defined
413
+ // in the spec. Thus, the users can always user lowercase, and if the field
414
+ // should be in mixed case, it will be. See P4::Spec::method_missing
415
+ //
416
+
417
+ VALUE
418
+ SpecMgr::SpecFields( const char *type )
419
+ {
420
+ return SpecFields( specs->GetVar( type ) );
421
+ }
422
+
423
+ VALUE
424
+ SpecMgr::SpecFields( StrPtr *specDef )
425
+ {
426
+ if( !specDef ) return Qnil;
427
+
428
+ //
429
+ // Here we abuse the fact that SpecElem::tag is public, even though it's
430
+ // only supposed to be public to SpecData's subclasses. It's hard to
431
+ // see that changing anytime soon, and it makes this so simple and
432
+ // reliable. So...
433
+ //
434
+ VALUE hash = rb_hash_new();
435
+ Error e;
436
+
437
+ #if P4APIVER_ID >= 513538
438
+ Spec s( specDef->Text(), "", &e );
439
+ #else
440
+ Spec s( specDef->Text(), "" );
441
+ #endif
442
+ if( e.Test() ) return Qnil;
443
+
444
+ for( int i = 0; i < s.Count(); i++ )
445
+ {
446
+ StrBuf k;
447
+ StrBuf v;
448
+ SpecElem * se = s.Get( i );
449
+
450
+ v = se->tag;
451
+ k = v;
452
+ StrOps::Lower( k );
453
+
454
+ rb_hash_aset(hash,
455
+ P4Utils::ruby_string( k.Text(), k.Length() ),
456
+ P4Utils::ruby_string( v.Text(), v.Length() ) );
457
+ }
458
+ return hash;
459
+ }
460
+
461
+ //
462
+ // Split a key into its base name and its index. i.e. for a key "how1,0"
463
+ // the base name is "how" and they index is "1,0". We work backwards from
464
+ // the end of the key looking for the first char that is neither a
465
+ // digit, nor a comma.
466
+ //
467
+
468
+ void
469
+ SpecMgr::SplitKey( const StrPtr *key, StrBuf &base, StrBuf &index )
470
+ {
471
+ int i = 0;
472
+
473
+ base = *key;
474
+ index = "";
475
+ for ( i = key->Length(); i; i-- )
476
+ {
477
+ char prev = (*key)[ i-1 ];
478
+ if ( !isdigit( prev ) && prev != ',' )
479
+ {
480
+ base.Set( key->Text(), i );
481
+ index.Set( key->Text() + i );
482
+ break;
483
+ }
484
+ }
485
+ }
486
+
487
+ //
488
+ // Insert an element into the response structure. The element may need to
489
+ // be inserted into an array nested deeply within the enclosing hash.
490
+ //
491
+
492
+ void
493
+ SpecMgr::InsertItem( VALUE hash, const StrPtr *var, const StrPtr *val )
494
+ {
495
+ VALUE ary = 0;
496
+ VALUE tary = 0;
497
+ VALUE key;
498
+ ID idLength = rb_intern( "length" );
499
+ StrBuf base, index;
500
+ StrRef comma( "," );
501
+
502
+ SplitKey( var, base, index );
503
+
504
+ // If there's no index, then we insert into the top level hash
505
+ // but if the key is already defined then we need to rename the key. This
506
+ // is probably one of those special keys like otherOpen which can be
507
+ // both an array element and a scalar. The scalar comes last, so we
508
+ // just rename it to "otherOpens" to avoid trashing the previous key
509
+ // value
510
+ if ( index == "" )
511
+ {
512
+ ID idHasKey = rb_intern( "has_key?");
513
+ ID idPlus = rb_intern( "+" );
514
+
515
+ key = P4Utils::ruby_string( var->Text() );
516
+ if ( rb_funcall( hash, idHasKey, 1, key ) == Qtrue )
517
+ key = rb_funcall( key, idPlus, 1, P4Utils::ruby_string( "s" ) );
518
+
519
+ if( P4RDB_DATA )
520
+ fprintf( stderr, "... %s -> %s\n", StringValuePtr( key ), val->Text() );
521
+
522
+ rb_hash_aset( hash, key, P4Utils::ruby_string( val->Text() ) );
523
+ return;
524
+ }
525
+
526
+ //
527
+ // Get or create the parent array from the hash.
528
+ //
529
+ key = P4Utils::ruby_string( base.Text() );
530
+ ary = rb_hash_aref( hash, key );
531
+
532
+ if ( Qnil == ary )
533
+ {
534
+ ary = rb_ary_new();
535
+ rb_hash_aset( hash, key, ary );
536
+ }
537
+ else if( rb_obj_is_kind_of( ary, rb_cArray ) != Qtrue )
538
+ {
539
+ //
540
+ // There's an index in our var name, but the name is already defined
541
+ // and the value it contains is not an array. This means we've got a
542
+ // name collision. This can happen in 'p4 diff2' for example, when
543
+ // one file gets 'depotFile' and the other gets 'depotFile2'. In
544
+ // these cases it makes sense to keep the structure flat so we
545
+ // just use the raw variable name.
546
+ //
547
+ if( P4RDB_DATA )
548
+ fprintf( stderr, "... %s -> %s\n", var->Text(), val->Text() );
549
+
550
+ rb_hash_aset( hash, P4Utils::ruby_string( var->Text() ) ,
551
+ P4Utils::ruby_string( val->Text() ) );
552
+ return;
553
+ }
554
+
555
+ // The index may be a simple digit, or it could be a comma separated
556
+ // list of digits. For each "level" in the index, we need a containing
557
+ // array.
558
+ if( P4RDB_DATA )
559
+ fprintf( stderr, "... %s -> [", base.Text() );
560
+
561
+ for( const char *c = 0 ; ( c = index.Contains( comma ) ); )
562
+ {
563
+ StrBuf level;
564
+ level.Set( index.Text(), c - index.Text() );
565
+ index.Set( c + 1 );
566
+
567
+ // Found another level so we need to get/create a nested array
568
+ // under the current entry. We use the level as an index so that
569
+ // missing entries are left empty deliberately.
570
+
571
+ tary = rb_ary_entry( ary, level.Atoi() );
572
+ if ( ! RTEST( tary ) )
573
+ {
574
+ tary = rb_ary_new();
575
+ rb_ary_store( ary, level.Atoi(), tary );
576
+ }
577
+ if( P4RDB_DATA )
578
+ fprintf( stderr, "%s][", level.Text() );
579
+ ary = tary;
580
+ }
581
+ int pos = index.Atoi();
582
+
583
+ if( P4RDB_DATA )
584
+ fprintf( stderr, "%d] = %s\n", pos, val->Text() );
585
+
586
+ rb_ary_store( ary, pos, P4Utils::ruby_string( val->Text() ) );
587
+ }
588
+
589
+ //
590
+ // Create a new P4::Spec object and return it.
591
+ //
592
+
593
+ VALUE
594
+ SpecMgr::NewSpec( StrPtr *specDef )
595
+ {
596
+ ID idNew = rb_intern( "new" );
597
+ ID idP4 = rb_intern( "P4" );
598
+ ID idP4Spec = rb_intern( "Spec" );
599
+ VALUE cP4 = rb_const_get_at( rb_cObject, idP4 );
600
+ VALUE cP4Spec = rb_const_get_at( cP4, idP4Spec );
601
+ VALUE fields = SpecFields( specDef );
602
+
603
+ return rb_funcall( cP4Spec, idNew, 1, fields );
604
+ }