p4ruby 2022.1.2359956-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,841 @@
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 : p4clientapi.cc
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Ruby bindings for the Perforce API. Main interface to the
34
+ * Perforce API.
35
+ *
36
+ ******************************************************************************/
37
+ #include <ruby.h>
38
+ #include "undefdups.h"
39
+ #include <p4/clientapi.h>
40
+ #include <p4/strtable.h>
41
+ #include <p4/i18napi.h>
42
+ #include <p4/enviro.h>
43
+ #include <p4/hostenv.h>
44
+ #include <p4/spec.h>
45
+ #include <p4/ignore.h>
46
+ #include <p4/debug.h>
47
+ #include "p4result.h"
48
+ #include "p4rubydebug.h"
49
+ #include "clientuserruby.h"
50
+ #include "specmgr.h"
51
+ #include "p4clientapi.h"
52
+ #include "p4utils.h"
53
+
54
+
55
+
56
+ /*******************************************************************************
57
+ * Our Ruby classes.
58
+ ******************************************************************************/
59
+ extern VALUE cP4; // Base P4 class
60
+ extern VALUE eP4; // Exception class
61
+
62
+
63
+ P4ClientApi::P4ClientApi() : ui( &specMgr )
64
+ {
65
+ debug = 0;
66
+ server2 = 0;
67
+ depth = 0;
68
+ exceptionLevel = 2;
69
+ maxResults = 0;
70
+ maxScanRows = 0;
71
+ maxLockTime = 0;
72
+ InitFlags();
73
+ apiLevel = atoi( P4Tag::l_client );
74
+ enviro = new Enviro;
75
+ prog = "unnamed p4ruby script";
76
+
77
+ client.SetProtocol( "specstring", "" );
78
+
79
+ //
80
+ // Load any P4CONFIG file
81
+ //
82
+ HostEnv henv;
83
+ StrBuf cwd;
84
+
85
+ henv.GetCwd( cwd, enviro );
86
+ if( cwd.Length() )
87
+ enviro->Config( cwd );
88
+
89
+ //
90
+ // Load the current ticket file. Start with the default, and then
91
+ // override it if P4TICKETS is set.
92
+ //
93
+ const char *t;
94
+
95
+ henv.GetTicketFile( ticketFile );
96
+
97
+ if( (t = enviro->Get("P4TICKETS")) )
98
+ ticketFile = t;
99
+
100
+ //
101
+ // Load the current trust file. Start with the default, and then
102
+ // override it if P4TRUST is set.
103
+ //
104
+
105
+ henv.GetTrustFile( trustFile );
106
+
107
+ if( (t = enviro->Get("P4TICKETS")) )
108
+ trustFile = t;
109
+
110
+ //
111
+ // Load the current P4CHARSET if set.
112
+ //
113
+ if( client.GetCharset().Length() )
114
+ SetCharset( client.GetCharset().Text() );
115
+ }
116
+
117
+ P4ClientApi::~P4ClientApi()
118
+ {
119
+ if ( IsConnected() )
120
+ {
121
+ Error e;
122
+ client.Final( &e );
123
+ // Ignore errors
124
+ }
125
+ delete enviro;
126
+ }
127
+
128
+ const char *
129
+ P4ClientApi::GetEnv( const char *v)
130
+ {
131
+ return enviro->Get( v );
132
+ }
133
+
134
+ void
135
+ P4ClientApi::SetEnviroFile( const char *c )
136
+ {
137
+ enviro->SetEnviroFile(c);
138
+ }
139
+
140
+ const StrPtr *
141
+ P4ClientApi::GetEnviroFile()
142
+ {
143
+ return enviro->GetEnviroFile();
144
+ }
145
+
146
+ void
147
+ P4ClientApi::SetEVar( const char *var, const char *val )
148
+ {
149
+ StrRef sVar( var );
150
+ StrRef sVal( val );
151
+ client.SetEVar( sVar, sVal );
152
+ }
153
+
154
+ const StrPtr *
155
+ P4ClientApi::GetEVar( const char *var )
156
+ {
157
+ StrRef sVar( var );
158
+ return client.GetEVar( sVar );
159
+ }
160
+
161
+ void
162
+ P4ClientApi::SetApiLevel( int level )
163
+ {
164
+ StrBuf b;
165
+ b << level;
166
+ apiLevel = level;
167
+ client.SetProtocol( "api", b.Text() );
168
+ ui.SetApiLevel( level );
169
+ }
170
+
171
+ int
172
+ P4ClientApi::SetCharset( const char *c )
173
+ {
174
+ StrRef cs_none( "none" );
175
+
176
+ if( P4RDB_COMMANDS )
177
+ fprintf( stderr, "[P4] Setting charset: %s\n", c );
178
+
179
+ if( c && cs_none != c )
180
+ {
181
+ CharSetApi::CharSet cs = CharSetApi::Lookup( c );
182
+ if( cs < 0 )
183
+ {
184
+ StrBuf m;
185
+ m = "Unknown or unsupported charset: ";
186
+ m.Append( c );
187
+ Except( "P4#charset=", m.Text() );
188
+ }
189
+ #ifdef HAVE_RUBY_ENCODING_H
190
+ CharSetApi::CharSet utf8 = CharSetApi::Lookup( "utf8" );
191
+ client.SetTrans( utf8, cs, utf8, utf8 );
192
+ #else
193
+ client.SetTrans( cs, cs, cs, cs );
194
+ #endif
195
+ client.SetCharset( c );
196
+ P4Utils::SetCharset( c );
197
+ }
198
+ else
199
+ {
200
+ // Disables automatic unicode detection if called
201
+ // prior to init (2014.2)
202
+ client.SetTrans( 0 );
203
+ }
204
+ return 1;
205
+ }
206
+
207
+ void
208
+ P4ClientApi::SetCwd( const char *c )
209
+ {
210
+ client.SetCwd( c );
211
+ enviro->Config( StrRef( c ) );
212
+ }
213
+
214
+ void
215
+ P4ClientApi::SetTicketFile( const char *p )
216
+ {
217
+ client.SetTicketFile( p );
218
+ ticketFile = p;
219
+ }
220
+
221
+ void
222
+ P4ClientApi::SetTrustFile( const char *p )
223
+ {
224
+ client.SetTrustFile( p );
225
+ trustFile = p;
226
+ }
227
+
228
+ void
229
+ P4ClientApi::SetDebug( int d )
230
+ {
231
+ debug = d;
232
+ ui.SetDebug( d );
233
+ specMgr.SetDebug( d );
234
+
235
+ if( P4RDB_RPC )
236
+ p4debug.SetLevel( "rpc=5" );
237
+ else
238
+ p4debug.SetLevel( "rpc=0" );
239
+
240
+ if( P4RDB_SSL )
241
+ p4debug.SetLevel( "ssl=3" );
242
+ else
243
+ p4debug.SetLevel( "ssl=0" );
244
+ }
245
+
246
+ void
247
+ P4ClientApi::SetArrayConversion( int i )
248
+ {
249
+ specMgr.SetArrayConversion( i );
250
+ }
251
+
252
+ void
253
+ P4ClientApi::SetProtocol( const char *var, const char *val )
254
+ {
255
+ client.SetProtocol( var, val );
256
+ }
257
+
258
+ VALUE
259
+ P4ClientApi::SetEnv( const char *var, const char *val )
260
+ {
261
+ Error e;
262
+
263
+ enviro->Set( var, val, &e );
264
+ if( e.Test() && exceptionLevel )
265
+ {
266
+ Except( "P4#set_env", &e );
267
+ }
268
+
269
+ if( e.Test() )
270
+ return Qfalse;
271
+
272
+ // Fixes an issue on OS X where the next enviro->Get doesn't return the
273
+ // cached value
274
+ enviro->Reload();
275
+
276
+ return Qtrue;
277
+ }
278
+
279
+ //
280
+ // connect to the Perforce server.
281
+ //
282
+
283
+ VALUE
284
+ P4ClientApi::Connect()
285
+ {
286
+ if ( P4RDB_COMMANDS )
287
+ fprintf( stderr, "[P4] Connecting to Perforce\n" );
288
+
289
+ if ( IsConnected() )
290
+ {
291
+ rb_warn( "P4#connect - Perforce client already connected!" );
292
+ return Qtrue;
293
+ }
294
+
295
+ return ConnectOrReconnect();
296
+ }
297
+
298
+ VALUE
299
+ P4ClientApi::ConnectOrReconnect()
300
+ {
301
+ if ( IsTrackMode() )
302
+ client.SetProtocol( "track", "" );
303
+
304
+ Error e;
305
+
306
+ ResetFlags();
307
+ client.Init( &e );
308
+ if ( e.Test() && exceptionLevel )
309
+ Except( "P4#connect", &e );
310
+
311
+ if ( e.Test() )
312
+ return Qfalse;
313
+
314
+ // If a handler is defined, reset the break functionality
315
+ // for the KeepAlive function
316
+
317
+ if( ui.GetHandler() != Qnil )
318
+ {
319
+ client.SetBreak( &ui );
320
+ }
321
+
322
+ SetConnected();
323
+ return Qtrue;
324
+ }
325
+
326
+
327
+ //
328
+ // Disconnect session
329
+ //
330
+ VALUE
331
+ P4ClientApi::Disconnect()
332
+ {
333
+ if ( P4RDB_COMMANDS )
334
+ fprintf( stderr, "[P4] Disconnect\n" );
335
+
336
+ if ( !IsConnected() )
337
+ {
338
+ rb_warn( "P4#disconnect - not connected" );
339
+ return Qtrue;
340
+ }
341
+ Error e;
342
+ client.Final( &e );
343
+ ResetFlags();
344
+
345
+ // Clear the specdef cache.
346
+ specMgr.Reset();
347
+
348
+ // Clear out any results from the last command
349
+ ui.Reset();
350
+
351
+ return Qtrue;
352
+ }
353
+
354
+ //
355
+ // Test whether or not connected
356
+ //
357
+ VALUE
358
+ P4ClientApi::Connected()
359
+ {
360
+ if( IsConnected() && !client.Dropped() )
361
+ return Qtrue;
362
+ else if( IsConnected() )
363
+ Disconnect();
364
+ return Qfalse;
365
+ }
366
+
367
+ void
368
+ P4ClientApi::Tagged( int enable )
369
+ {
370
+ if( enable )
371
+ SetTag();
372
+ else
373
+ ClearTag();
374
+ }
375
+
376
+ int P4ClientApi::SetTrack( int enable )
377
+ {
378
+ if ( IsConnected() ) {
379
+ if( exceptionLevel )
380
+ {
381
+ Except( "P4#track=", "Can't change performance tracking once you've connected.");
382
+ }
383
+ return Qfalse;
384
+ }
385
+ else if ( enable ) {
386
+ SetTrackMode();
387
+ ui.SetTrack(true);
388
+ }
389
+ else {
390
+ ClearTrackMode();
391
+ ui.SetTrack(false);
392
+ }
393
+ return Qtrue;
394
+ }
395
+
396
+ void P4ClientApi::SetStreams( int enable )
397
+ {
398
+ if ( enable )
399
+ SetStreamsMode();
400
+ else
401
+ ClearStreamsMode();
402
+ }
403
+
404
+ void P4ClientApi::SetGraph( int enable )
405
+ {
406
+ if ( enable )
407
+ SetGraphMode();
408
+ else
409
+ ClearGraphMode();
410
+ }
411
+
412
+ int
413
+ P4ClientApi::GetServerLevel()
414
+ {
415
+ if( !IsConnected() )
416
+ Except( "server_level", "Not connected to a Perforce Server.");
417
+ if( !IsCmdRun() )
418
+ Run( "info", 0, 0 );
419
+ return server2;
420
+ }
421
+
422
+ int
423
+ P4ClientApi::ServerCaseSensitive()
424
+ {
425
+ if( !IsConnected() )
426
+ Except( "server_case_sensitive?", "Not connected to a Perforce Server.");
427
+ if( !IsCmdRun() )
428
+ Run( "info", 0, 0);
429
+ return !IsCaseFold();
430
+ }
431
+
432
+ int
433
+ P4ClientApi::ServerUnicode()
434
+ {
435
+ if( !IsConnected() )
436
+ Except( "server_unicode?", "Not connected to a Perforce Server.");
437
+ if( !IsCmdRun() )
438
+ Run( "info", 0, 0);
439
+ return IsUnicode();
440
+ }
441
+
442
+
443
+ // Check if the supplied path falls within the view of the ignore file
444
+ int
445
+ P4ClientApi::IsIgnored( const char *path )
446
+ {
447
+ Ignore *ignore = client.GetIgnore();
448
+ if( !ignore ) return 0;
449
+
450
+ StrRef p( path );
451
+ return ignore->Reject( p, client.GetIgnoreFile() );
452
+ }
453
+
454
+ //
455
+ // Run returns the results of the command. If the client has not been
456
+ // connected, then an exception is raised but errors from Perforce
457
+ // commands are returned via the Errors() and ErrorCount() interfaces
458
+ // and not via exceptions because one failure in a command applied to many
459
+ // files would interrupt processing of all the other files if an exception
460
+ // is raised.
461
+ //
462
+
463
+ VALUE
464
+ P4ClientApi::Run( const char *cmd, int argc, char * const *argv )
465
+ {
466
+ // Save the entire command string for our error messages. Makes it
467
+ // easy to see where a script has gone wrong.
468
+ StrBuf cmdString;
469
+ cmdString << "\"p4 " << cmd;
470
+ for( int i = 0; i < argc; i++ )
471
+ cmdString << " " << argv[ i ];
472
+ cmdString << "\"";
473
+
474
+ if ( P4RDB_COMMANDS )
475
+ fprintf( stderr, "[P4] Executing %s\n", cmdString.Text() );
476
+
477
+ if ( depth )
478
+ {
479
+ rb_warn( "Can't execute nested Perforce commands." );
480
+ return Qfalse;
481
+ }
482
+
483
+ // Clear out any results from the previous command
484
+ ui.Reset();
485
+
486
+ if ( !IsConnected() && exceptionLevel )
487
+ Except( "P4#run", "not connected." );
488
+
489
+ if ( !IsConnected() )
490
+ return Qfalse;
491
+
492
+ // Tell the UI which command we're running.
493
+ ui.SetCommand( cmd );
494
+
495
+ depth++;
496
+ RunCmd( cmd, &ui, argc, argv );
497
+ depth--;
498
+
499
+ if( ui.GetHandler() != Qnil) {
500
+ if( client.Dropped() && ! ui.IsAlive() ) {
501
+ Disconnect();
502
+ ConnectOrReconnect();
503
+ }
504
+ }
505
+
506
+ ui.RaiseRubyException();
507
+
508
+ P4Result &results = ui.GetResults();
509
+
510
+ if ( results.ErrorCount() && exceptionLevel )
511
+ Except( "P4#run", "Errors during command execution", cmdString.Text() );
512
+
513
+ if ( results.WarningCount() && exceptionLevel > 1 )
514
+ Except( "P4#run", "Warnings during command execution",cmdString.Text());
515
+
516
+ return results.GetOutput();
517
+ }
518
+
519
+
520
+ void
521
+ P4ClientApi::RunCmd( const char *cmd, ClientUser *ui, int argc, char * const *argv )
522
+ {
523
+ client.SetProg( &prog );
524
+ if( version.Length() )
525
+ client.SetVersion( &version );
526
+
527
+ if( IsTag() )
528
+ client.SetVar( "tag" );
529
+
530
+ if ( IsStreams() && apiLevel > 69 )
531
+ client.SetVar( "enableStreams", "" );
532
+
533
+ if ( IsGraph() && apiLevel > 81 )
534
+ client.SetVar( "enableGraph", "" );
535
+
536
+ // If maxresults or maxscanrows is set, enforce them now
537
+ if( maxResults ) client.SetVar( "maxResults", maxResults );
538
+ if( maxScanRows ) client.SetVar( "maxScanRows", maxScanRows );
539
+ if( maxLockTime ) client.SetVar( "maxLockTime", maxLockTime );
540
+
541
+ // If progress is set, set progress var.
542
+ if( ( (ClientUserRuby*)ui)->GetProgress() != Qnil ) client.SetVar( P4Tag::v_progress, 1 );
543
+
544
+ client.SetArgv( argc, argv );
545
+ client.Run( cmd, ui );
546
+
547
+ // Can only read the protocol block *after* a command has been run.
548
+ // Do this once only.
549
+ if( !IsCmdRun() )
550
+ {
551
+ StrPtr *s = 0;
552
+ if ( (s = client.GetProtocol(P4Tag::v_server2)) )
553
+ server2 = s->Atoi();
554
+
555
+ if( (s = client.GetProtocol(P4Tag::v_unicode)) )
556
+ if( s->Atoi() )
557
+ SetUnicode();
558
+
559
+ if( (s = client.GetProtocol(P4Tag::v_nocase)) )
560
+ SetCaseFold();
561
+ }
562
+ SetCmdRun();
563
+ }
564
+
565
+
566
+ //
567
+ // Parses a string supplied by the user into a hash. To do this we need
568
+ // the specstring from the server. We try to cache those as we see them,
569
+ // but the user may not have executed any commands to allow us to cache
570
+ // them so we may have to fetch the spec first.
571
+ //
572
+
573
+ VALUE
574
+ P4ClientApi::ParseSpec( const char * type, const char *form )
575
+ {
576
+ if ( !specMgr.HaveSpecDef( type ) )
577
+ {
578
+ if( exceptionLevel )
579
+ {
580
+ StrBuf m;
581
+ m = "No spec definition for ";
582
+ m.Append( type );
583
+ m.Append( " objects." );
584
+ Except( "P4#parse_spec", m.Text() );
585
+ }
586
+ else
587
+ {
588
+ return Qfalse;
589
+ }
590
+ }
591
+
592
+ // Got a specdef so now we can attempt to parse it.
593
+ Error e;
594
+ VALUE v;
595
+ v = specMgr.StringToSpec( type, form, &e );
596
+
597
+ if ( e.Test() )
598
+ {
599
+ if( exceptionLevel )
600
+ Except( "P4#parse_spec", &e );
601
+ else
602
+ return Qfalse;
603
+ }
604
+
605
+ return v;
606
+ }
607
+
608
+
609
+ //
610
+ // Converts a hash supplied by the user into a string using the specstring
611
+ // from the server. We may have to fetch the specstring first.
612
+ //
613
+
614
+ VALUE
615
+ P4ClientApi::FormatSpec( const char * type, VALUE hash )
616
+ {
617
+ if ( !specMgr.HaveSpecDef( type ) )
618
+ {
619
+ if( exceptionLevel )
620
+ {
621
+ StrBuf m;
622
+ m = "No spec definition for ";
623
+ m.Append( type );
624
+ m.Append( " objects." );
625
+ Except( "P4#format_spec", m.Text() );
626
+ }
627
+ else
628
+ {
629
+ return Qfalse;
630
+ }
631
+ }
632
+
633
+ // Got a specdef so now we can attempt to convert.
634
+ StrBuf buf;
635
+ Error e;
636
+
637
+ specMgr.SpecToString( type, hash, buf, &e );
638
+ if( !e.Test() )
639
+ return P4Utils::ruby_string( buf.Text() );
640
+
641
+ if( exceptionLevel )
642
+ {
643
+ StrBuf m;
644
+ m = "Error converting hash to a string.";
645
+ if( e.Test() ) e.Fmt( m, EF_PLAIN );
646
+ Except( "P4#format_spec", m.Text() );
647
+ }
648
+ return Qnil;
649
+ }
650
+
651
+ //
652
+ // Returns a hash whose keys contain the names of the fields in a spec of the
653
+ // specified type. Not yet exposed to Ruby clients, but may be in future.
654
+ //
655
+ VALUE
656
+ P4ClientApi::SpecFields( const char * type )
657
+ {
658
+ if ( !specMgr.HaveSpecDef( type ) )
659
+ {
660
+ if( exceptionLevel )
661
+ {
662
+ StrBuf m;
663
+ m = "No spec definition for ";
664
+ m.Append( type );
665
+ m.Append( " objects." );
666
+ Except( "P4#spec_fields", m.Text() );
667
+ }
668
+ else
669
+ {
670
+ return Qfalse;
671
+ }
672
+ }
673
+
674
+ return specMgr.SpecFields( type );
675
+ }
676
+
677
+ //
678
+ // Raises an exception or returns Qfalse on bad input
679
+ //
680
+
681
+ VALUE
682
+ P4ClientApi::SetInput( VALUE input )
683
+ {
684
+ if ( P4RDB_COMMANDS )
685
+ fprintf( stderr, "[P4] Received input for next command\n" );
686
+
687
+ if ( ! ui.SetInput( input ) )
688
+ {
689
+ if ( exceptionLevel )
690
+ Except( "P4#input", "Error parsing supplied data." );
691
+ else
692
+ return Qfalse;
693
+ }
694
+ return Qtrue;
695
+ }
696
+
697
+ //
698
+ // Sets the handler and connects the SetBreak feature
699
+ //
700
+ VALUE
701
+ P4ClientApi::SetHandler( VALUE handler )
702
+ {
703
+ if ( P4RDB_COMMANDS )
704
+ fprintf( stderr, "[P4] Received handler object\n" );
705
+
706
+ ui.SetHandler( handler );
707
+
708
+ if( handler == Qnil)
709
+ client.SetBreak(NULL);
710
+ else
711
+ client.SetBreak(&ui);
712
+
713
+ return Qtrue;
714
+ }
715
+
716
+ VALUE
717
+ P4ClientApi::SetProgress( VALUE progress ) {
718
+ if ( P4RDB_COMMANDS )
719
+ fprintf( stderr, "[P4] Received progress object\n" );
720
+
721
+ return ui.SetProgress( progress );
722
+ }
723
+
724
+ VALUE
725
+ P4ClientApi::SetSSOHandler( VALUE h )
726
+ {
727
+ if ( P4RDB_COMMANDS )
728
+ fprintf( stderr, "[P4] Received SSO handler object\n" );
729
+
730
+ ui.SetRubySSOHandler( h );
731
+
732
+ return Qtrue;
733
+ }
734
+
735
+
736
+ void
737
+ P4ClientApi::GCMark()
738
+ {
739
+ if ( P4RDB_GC )
740
+ fprintf( stderr, "[P4] Ruby asked us to do garbage collection\n" );
741
+
742
+ // We don't hold Ruby objects. But our UI does.
743
+ ui.GCMark();
744
+ }
745
+
746
+ void
747
+ P4ClientApi::Except( const char *func, const char *msg )
748
+ {
749
+ StrBuf m;
750
+ StrBuf errors;
751
+ StrBuf warnings;
752
+ int terminate = 0;
753
+
754
+ m << "[" << func << "] " << msg;
755
+
756
+ // Now append any errors and warnings to the text
757
+ ui.GetResults().FmtErrors( errors );
758
+ ui.GetResults().FmtWarnings( warnings );
759
+
760
+ if( errors.Length() )
761
+ {
762
+ m << "\n" << errors;
763
+ terminate++;
764
+ }
765
+
766
+ if( exceptionLevel > 1 && warnings.Length() )
767
+ {
768
+ m << "\n" << warnings;
769
+ terminate++;
770
+ }
771
+
772
+ if( terminate )
773
+ m << "\n\n";
774
+
775
+ rb_raise( eP4, "%s", m.Text() );
776
+ }
777
+
778
+ void
779
+ P4ClientApi::Except( const char *func, const char *msg, const char *cmd )
780
+ {
781
+ StrBuf m;
782
+
783
+ m << msg;
784
+ m << "( " << cmd << " )";
785
+ Except( func, m.Text() );
786
+ }
787
+
788
+ void
789
+ P4ClientApi::Except( const char *func, Error *e )
790
+ {
791
+ StrBuf m;
792
+
793
+ e->Fmt( &m );
794
+ Except( func, m.Text() );
795
+ }
796
+
797
+ //
798
+ // SSO Handlers
799
+ //
800
+
801
+ VALUE
802
+ P4ClientApi::SetEnableSSO( VALUE e )
803
+ {
804
+ return ui.EnableSSO( e );
805
+ }
806
+
807
+ VALUE
808
+ P4ClientApi::GetEnableSSO()
809
+ {
810
+ return ui.SSOEnabled();
811
+ }
812
+
813
+ VALUE
814
+ P4ClientApi::GetSSOVars()
815
+ {
816
+ return ui.GetSSOVars();
817
+ }
818
+
819
+ VALUE
820
+ P4ClientApi::SetSSOPassResult( VALUE r )
821
+ {
822
+ return ui.SetSSOPassResult( r );
823
+ }
824
+
825
+ VALUE
826
+ P4ClientApi::GetSSOPassResult()
827
+ {
828
+ return ui.GetSSOPassResult();
829
+ }
830
+
831
+ VALUE
832
+ P4ClientApi::SetSSOFailResult( VALUE r )
833
+ {
834
+ return ui.SetSSOFailResult( r );
835
+ }
836
+
837
+ VALUE
838
+ P4ClientApi::GetSSOFailResult()
839
+ {
840
+ return ui.GetSSOFailResult();
841
+ }