/******************************************************************************* Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ /******************************************************************************* * Name : p4.cc * * Author : Tony Smith <tony@perforce.com> or <tony@smee.org> * * Description : Ruby bindings for the Perforce API. * * vim:ts=8:sw=4 ******************************************************************************/ #include <ruby.h> #include "undefdups.h" #include <p4/clientapi.h> #include <p4/strtable.h> #include <p4/spec.h> #include <p4/ident.h> #include "p4result.h" #include "specmgr.h" #include "clientuserruby.h" #include "p4rubyconf.h" #include "p4clientapi.h" #include "p4mergedata.h" #include "p4mapmaker.h" #include "p4error.h" #include "p4utils.h" #include "extconf.h" // Our Ident mechanism doesn't really translate to a semantic versioning scheme, // So it's been simply replaced by the current version string. We'll see if that // needs to change, since a lot of the information this displayed is available // via RbConfig locally. //static Ident ident = { // IdentMagic "P4RUBY " P4RUBY_VERSION //}; /******************************************************************************* * Our Ruby classes. ******************************************************************************/ VALUE cP4; // Base P4 Class VALUE eP4; // Exception class VALUE cP4MD; // P4::MergeData class VALUE cP4Map; // P4::Map class VALUE cP4Msg; // P4::Message class VALUE cP4Prog; // P4::Progress class extern "C" { // // Construction/destruction // static void p4_free( P4ClientApi *p4 ) { delete p4; } static void p4_mark( P4ClientApi *p4 ) { p4->GCMark(); } static VALUE p4_new( VALUE pClass ) { VALUE argv[ 1 ]; P4ClientApi *p4 = new P4ClientApi(); VALUE self; self = Data_Wrap_Struct( pClass, p4_mark, p4_free, p4 ); rb_obj_call_init( self, 0, argv ); return self; } // // Session connect/disconnect // static VALUE p4_connect( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->Connect(); } static VALUE p4_disconnect( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->Disconnect(); } static VALUE p4_connected( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->Connected(); } static VALUE p4_server_case_sensitive( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); if( p4->ServerCaseSensitive() ) return Qtrue; return Qfalse; } static VALUE p4_server_unicode( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); if( p4->ServerUnicode() ) return Qtrue; return Qfalse; } static VALUE p4_run_tagged( VALUE self, VALUE tagged ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); if( ! rb_block_given_p() ) rb_raise( rb_eArgError, "P4#run_tagged requires a block" ); // The user might have passed an integer, or it might be a boolean, // we convert to int for consistency. int flag = 0; if( tagged == Qtrue ) flag = 1; else if( tagged == Qfalse ) flag = 0; else flag = NUM2INT( tagged ) ? 1 : 0; int old_value = p4->IsTagged(); p4->Tagged( flag ); VALUE ret_val; // // XXX: This should perhaps be protected with rb_ensure()... // ret_val = rb_yield( self ); p4->Tagged( old_value ); return ret_val; } static VALUE p4_get_tagged( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->IsTagged() ? Qtrue : Qfalse; } static VALUE p4_set_tagged( VALUE self, VALUE toggle ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); // The user might have passed an integer, or it might be a boolean, // we convert to int for consistency. int flag = 0; if( toggle == Qtrue ) flag = 1; else if( toggle == Qfalse ) flag = 0; else flag = NUM2INT( toggle ) ? 1 : 0; p4->Tagged( flag ); return flag ? Qtrue : Qfalse; // Seems to be ignored... } static VALUE p4_get_api_level( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return INT2NUM( p4->GetApiLevel() ); } static VALUE p4_set_api_level( VALUE self, VALUE level ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetApiLevel( NUM2INT( level ) ); return self; } // // Getting/Setting Perforce environment // static VALUE p4_get_charset( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr c = p4->GetCharset(); return P4Utils::ruby_string( c.Text() ); } static VALUE p4_set_charset( VALUE self, VALUE c ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); // p4.charset = nil prior to connect can be used to // disable automatic charset detection if( c == Qnil ) return p4->SetCharset( 0 ); return p4->SetCharset( StringValuePtr( c ) ); } static VALUE p4_get_p4config( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr c = p4->GetConfig(); return P4Utils::ruby_string( c.Text() ); } static VALUE p4_get_cwd( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr cwd = p4->GetCwd(); return P4Utils::ruby_string( cwd.Text() ); } static VALUE p4_set_cwd( VALUE self, VALUE cwd ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetCwd( StringValuePtr( cwd ) ); return Qtrue; } static VALUE p4_get_client( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr client = p4->GetClient(); return P4Utils::ruby_string( client.Text() ); } static VALUE p4_set_client( VALUE self, VALUE client ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetClient( StringValuePtr( client ) ); return Qtrue; } static VALUE p4_get_env( VALUE self, VALUE var ) { P4ClientApi *p4; const char *val; Data_Get_Struct( self, P4ClientApi, p4 ); val = p4->GetEnv( StringValuePtr( var ) ); if( !val ) return Qnil; return P4Utils::ruby_string( val ); } static VALUE p4_set_env( VALUE self, VALUE var, VALUE val ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->SetEnv( StringValuePtr( var ), StringValuePtr( val ) ); } static VALUE p4_get_host( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr host = p4->GetHost(); return P4Utils::ruby_string( host.Text() ); } static VALUE p4_set_host( VALUE self, VALUE host ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetHost( StringValuePtr( host ) ); return Qtrue; } static VALUE p4_get_ignore( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr ignore = p4->GetIgnoreFile(); return P4Utils::ruby_string( ignore.Text() ); } static VALUE p4_set_ignore( VALUE self, VALUE file ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetIgnoreFile( StringValuePtr( file ) ); return Qtrue; } static VALUE p4_is_ignored( VALUE self, VALUE path ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); if( p4->IsIgnored( StringValuePtr( path ) ) ) return Qtrue; return Qfalse; } static VALUE p4_get_language( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr lang = p4->GetLanguage(); return P4Utils::ruby_string( lang.Text() ); } static VALUE p4_set_language( VALUE self, VALUE lang ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetLanguage( StringValuePtr( lang ) ); return Qtrue; } static VALUE p4_get_maxresults( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return INT2NUM( p4->GetMaxResults() ); } static VALUE p4_set_maxresults( VALUE self, VALUE val ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetMaxResults( NUM2INT( val ) ); return Qtrue; } static VALUE p4_get_maxscanrows( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return INT2NUM( p4->GetMaxScanRows() ); } static VALUE p4_set_maxscanrows( VALUE self, VALUE val ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetMaxScanRows( NUM2INT( val ) ); return Qtrue; } static VALUE p4_get_maxlocktime( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return INT2NUM( p4->GetMaxLockTime() ); } static VALUE p4_set_maxlocktime( VALUE self, VALUE val ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetMaxLockTime( NUM2INT( val ) ); return Qtrue; } static VALUE p4_get_password( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr passwd = p4->GetPassword(); return P4Utils::ruby_string( passwd.Text() ); } static VALUE p4_set_password( VALUE self, VALUE passwd ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetPassword( StringValuePtr( passwd ) ); return Qtrue; } static VALUE p4_get_port( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr port = p4->GetPort(); return P4Utils::ruby_string( port.Text() ); } static VALUE p4_set_port( VALUE self, VALUE port ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); if( p4->Connected() ) rb_raise( eP4, "Can't change port once you've connected." ); p4->SetPort( StringValuePtr( port ) ); return Qtrue; } static VALUE p4_get_prog( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return P4Utils::ruby_string( p4->GetProg().Text() ); } static VALUE p4_set_prog( VALUE self, VALUE prog ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetProg( StringValuePtr( prog ) ); return Qtrue; } static VALUE p4_set_protocol( VALUE self, VALUE var, VALUE val ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetProtocol( StringValuePtr( var ), StringValuePtr( val ) ); return Qtrue; } static VALUE p4_get_ticket_file( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return P4Utils::ruby_string( p4->GetTicketFile().Text() ); } static VALUE p4_set_ticket_file( VALUE self, VALUE path ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetTicketFile( StringValuePtr( path ) ); return Qtrue; } static VALUE p4_get_user( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); StrPtr user = p4->GetUser(); return P4Utils::ruby_string( user.Text() ); } static VALUE p4_set_user( VALUE self, VALUE user ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetUser( StringValuePtr( user ) ); return Qtrue; } static VALUE p4_get_version( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return P4Utils::ruby_string( p4->GetVersion().Text() ); } static VALUE p4_set_version( VALUE self, VALUE version ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetVersion( StringValuePtr( version ) ); return Qtrue; } static VALUE p4_get_track( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetTrack() ? Qtrue : Qfalse; } static VALUE p4_set_track( VALUE self, VALUE toggle ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); // The user might have passed an integer, or it might be a boolean, // we convert to int for consistency. int flag = 0; if( toggle == Qtrue ) flag = 1; else if( toggle == Qfalse ) flag = 0; else flag = NUM2INT( toggle ) ? 1 : 0; p4->SetTrack( flag ); return flag ? Qtrue : Qfalse; // Seems to be ignored... } static VALUE p4_get_streams( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->IsStreams() ? Qtrue : Qfalse; } static VALUE p4_set_streams( VALUE self, VALUE toggle ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); // The user might have passed an integer, or it might be a boolean, // we convert to int for consistency. int flag = 0; if( toggle == Qtrue ) flag = 1; else if( toggle == Qfalse ) flag = 0; else flag = NUM2INT( toggle ) ? 1 : 0; p4->SetStreams( flag ); return flag ? Qtrue : Qfalse; // Seems to be ignored... } /******************************************************************************* * Running commands. General purpose Run method and method for supplying * input to "p4 xxx -i" commands ******************************************************************************/ static VALUE p4_run( VALUE self, VALUE args ) { int i; int argc = 0; ID idFlatten = rb_intern( "flatten" ); ID idLength = rb_intern( "length" ); ID idTo_S = rb_intern( "to_s" ); P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); // Flatten the args array, and extract the Perforce command leaving // the remaining args in the array. VALUE flatArgs = rb_funcall( args, idFlatten, 0 ); if ( ! NUM2INT( rb_funcall( flatArgs, idLength, 0 ) ) ) rb_raise( eP4, "P4#run requires an argument" ); VALUE v = rb_funcall( flatArgs, rb_intern( "shift" ), 0 ); char *cmd = StringValuePtr( v ); argc = NUM2INT( rb_funcall( flatArgs, idLength, 0 ) ); // Allocate storage on the stack so it's automatically reclaimed // when we exit. char **p4args = ALLOCA_N( char *, argc + 1 ); // Copy the args across for ( i = 0; i < argc; i++ ) { VALUE entry = rb_ary_entry( flatArgs, i ); VALUE v = rb_funcall( entry, idTo_S, 0 ); p4args[ i ] = StringValuePtr( v ); } p4args[ i ] = 0; // Run the command VALUE res = p4->Run( cmd, argc, p4args ); return res; } static VALUE p4_set_input( VALUE self, VALUE input ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->SetInput( input ); } static VALUE p4_get_errors( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetErrors(); } static VALUE p4_get_messages( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetMessages(); } static VALUE p4_get_warnings( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetWarnings(); } static VALUE p4_set_except_level( VALUE self, VALUE level ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->ExceptionLevel( NUM2INT(level) ); return level; } static VALUE p4_get_except_level( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return INT2NUM( p4->ExceptionLevel() ); } static VALUE p4_get_server_level( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); int level = p4->GetServerLevel(); return INT2NUM( level ); } static VALUE p4_parse_spec( VALUE self, VALUE type, VALUE form ) { P4ClientApi *p4; Check_Type( form, T_STRING ); Check_Type( type, T_STRING ); Data_Get_Struct( self, P4ClientApi, p4 ); return p4->ParseSpec( StringValuePtr(type), StringValuePtr(form) ); } static VALUE p4_format_spec( VALUE self, VALUE type, VALUE hash ) { P4ClientApi *p4; Check_Type( type, T_STRING ); Check_Type( hash, T_HASH ); Data_Get_Struct( self, P4ClientApi, p4 ); return p4->FormatSpec( StringValuePtr(type), hash ); } static VALUE p4_track_output( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetTrackOutput(); } /******************************************************************************* * Self identification ******************************************************************************/ static VALUE p4_identify( VALUE self ) { StrBuf s; s.Append("P4RUBY "); s.Append(P4RUBY_VERSION); s.Append(" P4API "); s.Append(P4APIVER_STRING); s.Append(" PATCHLEVEL "); s.Append(P4API_PATCHLEVEL_STRING); s.Append(" WITH_LIBS "); s.Append(WITH_LIBS); return P4Utils::ruby_string( s.Text() ); } /******************************************************************************* * Debugging support ******************************************************************************/ static VALUE p4_get_debug( VALUE self) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4); return INT2NUM( p4->GetDebug() ); } static VALUE p4_set_debug( VALUE self, VALUE debug ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetDebug( NUM2INT(debug) ); return Qtrue; } /******************************************************************************* * Handler support ******************************************************************************/ static VALUE p4_get_handler( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetHandler(); } static VALUE p4_set_handler( VALUE self, VALUE handler ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); p4->SetHandler( handler ); return Qtrue; } /******************************************************************************* * Progress support ******************************************************************************/ static VALUE p4_get_progress( VALUE self ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->GetProgress(); } static VALUE p4_set_progress( VALUE self, VALUE progress ) { P4ClientApi *p4; Data_Get_Struct( self, P4ClientApi, p4 ); return p4->SetProgress( progress ); } /******************************************************************************* * P4::MergeData methods. Construction/destruction defined elsewhere ******************************************************************************/ static VALUE p4md_getyourname( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetYourName(); } static VALUE p4md_gettheirname( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetTheirName(); } static VALUE p4md_getbasename( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetBaseName(); } static VALUE p4md_getyourpath( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetYourPath(); } static VALUE p4md_gettheirpath( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetTheirPath(); } static VALUE p4md_getbasepath( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetBasePath(); } static VALUE p4md_getresultpath( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetResultPath(); } static VALUE p4md_getmergehint( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetMergeHint(); } static VALUE p4md_runmerge( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->RunMergeTool(); } static VALUE p4md_getcontentresolve( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetContentResolveStatus(); } // // Additional methods added for action resolve // static VALUE p4md_getactionresolve( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetActionResolveStatus(); } static VALUE p4md_getyoursaction( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetYoursAction(); } static VALUE p4md_gettheiraction( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetTheirAction(); } static VALUE p4md_getmergeaction( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetMergeAction(); } static VALUE p4md_getactiontype( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetType(); } static VALUE p4md_getinfo( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetMergeInfo(); } static VALUE p4md_invalidate( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); md->Invalidate(); return self; } static VALUE p4md_tos( VALUE self ) { P4MergeData *md = 0; Data_Get_Struct( self, P4MergeData, md ); return md->GetString(); } /****************************************************************************** * P4::Map class ******************************************************************************/ static void p4map_free( P4MapMaker *m ) { delete m; } static VALUE p4map_new( int argc, VALUE *argv, VALUE pClass ) { //VALUE pClass; VALUE array; VALUE self; P4MapMaker *m = new P4MapMaker; // First arg is the class // pClass = argv[ 0 ]; // Now instantiate the new object. self = Data_Wrap_Struct( pClass, 0, p4map_free, m ); rb_obj_call_init( self, 0, argv ); if( argc ) { array = argv[ 0 ]; if( !rb_obj_is_kind_of( array, rb_cArray ) ) rb_raise( rb_eRuntimeError, "Not an array" ); StrBuf t; ID idLen = rb_intern( "length" ); int len; VALUE entry; // Now iterate over the array, inserting the mappings len = NUM2INT( rb_funcall( array, idLen, 0 ) ); for( int i = 0; i < len; i++ ) { entry = rb_ary_entry( array, i ); m->Insert( entry ); } } return self; } // // Joins the RHS of the first mapping with the LHS of the second, and // returns a new P4::Map object made up of the LHS of the first and the // RHS of the second where the joins match up. // static VALUE p4map_join( VALUE pClass, VALUE left, VALUE right ) { P4MapMaker * l = 0; P4MapMaker * r = 0; P4MapMaker * j = 0; VALUE m; VALUE argv[ 1 ]; Data_Get_Struct( left, P4MapMaker, l ); Data_Get_Struct( right, P4MapMaker, r ); j = P4MapMaker::Join( l, r ); if( !j ) return Qnil; m = Data_Wrap_Struct( pClass, 0, p4map_free, j ); rb_obj_call_init( m, 0, argv ); return m; } // // Debugging support // static VALUE p4map_inspect( VALUE self ) { P4MapMaker * m = 0; StrBuf b; StrBuf tb; tb.Alloc( 32 ); sprintf( tb.Text(), "%p", (void*) self ); tb.SetLength(); Data_Get_Struct( self, P4MapMaker, m ); b << "#<P4::Map:" << tb << "> "; m->Inspect( b ); return P4Utils::ruby_string( b.Text(), b.Length() ); } // // Insert a mapping into a P4::Map object. Can be called with either // one, or two arguments. If one, it's assumed to be a string containing // either a half-map, or both halves of the mapping. // static VALUE p4map_insert( int argc, VALUE *argv, VALUE self ) { P4MapMaker * m = 0; StrBuf t; Data_Get_Struct( self, P4MapMaker, m ); if( argc < 1 || argc > 2 ) rb_raise( rb_eArgError, "P4::Map#insert takes 1, or 2 arguments" ); if( argc == 1 ) { // A mapping with only a left hand side. m->Insert( *argv ); return self; } if( argc == 2 ) { // Separate left- and right-hand strings. VALUE left; VALUE right; left = *argv++; right = *argv; m->Insert( left, right ); } return self; } static VALUE p4map_clear( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); m->Clear(); return Qtrue; } static VALUE p4map_count( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); return INT2NUM( m->Count() ); } static VALUE p4map_empty( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); return m->Count() ? Qfalse : Qtrue; } static VALUE p4map_reverse( VALUE self ) { P4MapMaker * m = 0; P4MapMaker * m2 = 0; VALUE rval; VALUE argv[ 1 ]; Data_Get_Struct( self, P4MapMaker, m ); m2 = new P4MapMaker( *m ); m2->Reverse(); rval = Data_Wrap_Struct( cP4Map, 0, p4map_free, m2 ); rb_obj_call_init( rval, 0, argv ); return rval; } // // P4::Map#translate( string, fwd=true ) // static VALUE p4map_trans( int argc, VALUE *argv, VALUE self ) { P4MapMaker * m = 0; int fwd = 1; VALUE string; if( argc < 1 || argc > 2 ) rb_raise( rb_eArgError, "Invalid arguments to P4::Map#translate. " "Pass the string you wish to translate, and an optional " "boolean to indicate whether translation should be in " "the forward direction." ); argc--; string = *argv++; if( argc && *argv == Qfalse ) fwd = 0; Data_Get_Struct( self, P4MapMaker, m ); return m->Translate( string, fwd ); } static VALUE p4map_includes( VALUE self, VALUE string ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); if( m->Translate( string, 1 ) != Qnil ) return Qtrue; if( m->Translate( string, 0 ) != Qnil ) return Qtrue; return Qfalse; } static VALUE p4map_lhs( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); return m->Lhs(); } static VALUE p4map_rhs( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); return m->Rhs(); } static VALUE p4map_to_a( VALUE self ) { P4MapMaker * m = 0; Data_Get_Struct( self, P4MapMaker, m ); return m->ToA(); } /******************************************************************************* * P4::Message methods. Construction/destruction defined elsewhere ******************************************************************************/ static VALUE p4msg_get_severity( VALUE self ) { P4Error * e = 0; Data_Get_Struct( self, P4Error, e ); return e->GetSeverity(); } static VALUE p4msg_get_generic( VALUE self ) { P4Error * e = 0; Data_Get_Struct( self, P4Error, e ); return e->GetGeneric(); } static VALUE p4msg_get_text( VALUE self ) { P4Error * e = 0; Data_Get_Struct( self, P4Error, e ); return e->GetText(); } static VALUE p4msg_get_id( VALUE self ) { P4Error * e = 0; Data_Get_Struct( self, P4Error, e ); return e->GetId(); } static VALUE p4msg_inspect( VALUE self ) { P4Error * e = 0; Data_Get_Struct( self, P4Error, e ); return e->Inspect(); } /****************************************************************************** * Extension initialisation ******************************************************************************/ void Init_P4() { // Ruby instantiation eP4 = rb_define_class( "P4Exception", rb_eRuntimeError ); // We ensure this class already exists by loading the version file in P4.rb. // If we don't do this, calling things via rake might change the load order // in "interesting" ways. cP4 = rb_path2class("P4"); rb_define_singleton_method( cP4, "new", RUBY_METHOD_FUNC(p4_new), 0 ); // Protocol options rb_define_method( cP4, "api_level", RUBY_METHOD_FUNC(p4_get_api_level), 0); rb_define_method( cP4, "api_level=", RUBY_METHOD_FUNC(p4_set_api_level), 1); rb_define_method( cP4, "streams?", RUBY_METHOD_FUNC(p4_get_streams) , 0 ); rb_define_method( cP4, "streams=", RUBY_METHOD_FUNC(p4_set_streams) , 1 ); rb_define_method( cP4, "tagged", RUBY_METHOD_FUNC(p4_run_tagged), 1 ); rb_define_method( cP4, "tagged?", RUBY_METHOD_FUNC(p4_get_tagged), 0 ); rb_define_method( cP4, "tagged=", RUBY_METHOD_FUNC(p4_set_tagged), 1 ); rb_define_method( cP4, "track?", RUBY_METHOD_FUNC(p4_get_track) , 0 ); rb_define_method( cP4, "track=", RUBY_METHOD_FUNC(p4_set_track) , 1 ); // Perforce client settings. // rb_define_method( cP4, "charset", RUBY_METHOD_FUNC(p4_get_charset) , 0 ); rb_define_method( cP4, "charset=", RUBY_METHOD_FUNC(p4_set_charset) , 1 ); rb_define_method( cP4, "cwd", RUBY_METHOD_FUNC(p4_get_cwd) , 0 ); rb_define_method( cP4, "cwd=", RUBY_METHOD_FUNC(p4_set_cwd) , 1 ); rb_define_method( cP4, "client", RUBY_METHOD_FUNC(p4_get_client) , 0 ); rb_define_method( cP4, "client=", RUBY_METHOD_FUNC(p4_set_client) , 1 ); rb_define_method( cP4, "env", RUBY_METHOD_FUNC(p4_get_env) , 1 ); rb_define_method( cP4, "set_env", RUBY_METHOD_FUNC(p4_set_env) , 2 ); rb_define_method( cP4, "host", RUBY_METHOD_FUNC(p4_get_host) , 0 ); rb_define_method( cP4, "host=", RUBY_METHOD_FUNC(p4_set_host) , 1 ); rb_define_method( cP4, "ignore_file",RUBY_METHOD_FUNC(p4_get_ignore) , 0 ); rb_define_method( cP4, "ignore_file=",RUBY_METHOD_FUNC(p4_set_ignore), 1 ); rb_define_method( cP4, "ignored?", RUBY_METHOD_FUNC(p4_is_ignored) , 1 ); rb_define_method( cP4, "language", RUBY_METHOD_FUNC(p4_get_language), 0 ); rb_define_method( cP4, "language=", RUBY_METHOD_FUNC(p4_set_language), 1 ); rb_define_method( cP4, "p4config_file",RUBY_METHOD_FUNC(p4_get_p4config),0); rb_define_method( cP4, "password", RUBY_METHOD_FUNC(p4_get_password), 0 ); rb_define_method( cP4, "password=", RUBY_METHOD_FUNC(p4_set_password), 1 ); rb_define_method( cP4, "port", RUBY_METHOD_FUNC(p4_get_port) , 0 ); rb_define_method( cP4, "port=", RUBY_METHOD_FUNC(p4_set_port) , 1 ); rb_define_method( cP4, "prog", RUBY_METHOD_FUNC(p4_get_prog) , 0 ); rb_define_method( cP4, "prog=", RUBY_METHOD_FUNC(p4_set_prog) , 1 ); rb_define_method( cP4, "protocol", RUBY_METHOD_FUNC(p4_set_protocol), 2 ); rb_define_method( cP4, "ticket_file", RUBY_METHOD_FUNC(p4_get_ticket_file), 0 ); rb_define_method( cP4, "ticket_file=", RUBY_METHOD_FUNC(p4_set_ticket_file), 1 ); rb_define_method( cP4, "user", RUBY_METHOD_FUNC(p4_get_user) , 0 ); rb_define_method( cP4, "user=", RUBY_METHOD_FUNC(p4_set_user) , 1 ); rb_define_method( cP4, "version", RUBY_METHOD_FUNC(p4_get_version) , 0 ); rb_define_method( cP4, "version=", RUBY_METHOD_FUNC(p4_set_version) , 1 ); rb_define_method( cP4, "maxresults", RUBY_METHOD_FUNC(p4_get_maxresults),0); rb_define_method( cP4, "maxresults=",RUBY_METHOD_FUNC(p4_set_maxresults),1); rb_define_method( cP4, "maxscanrows", RUBY_METHOD_FUNC(p4_get_maxscanrows),0); rb_define_method( cP4, "maxscanrows=",RUBY_METHOD_FUNC(p4_set_maxscanrows), 1 ); rb_define_method( cP4, "maxlocktime", RUBY_METHOD_FUNC(p4_get_maxlocktime), 0 ); rb_define_method( cP4, "maxlocktime=", RUBY_METHOD_FUNC(p4_set_maxlocktime), 1 ); // Session Connect/Disconnect rb_define_method( cP4, "connect", RUBY_METHOD_FUNC(p4_connect) , 0 ); rb_define_method( cP4, "connected?",RUBY_METHOD_FUNC(p4_connected) , 0 ); rb_define_method( cP4, "disconnect", RUBY_METHOD_FUNC(p4_disconnect) , 0 ); // Running commands - general purpose commands rb_define_method( cP4, "run", RUBY_METHOD_FUNC(p4_run) ,-2 ); rb_define_method( cP4, "input=", RUBY_METHOD_FUNC(p4_set_input) , 1 ); rb_define_method( cP4, "errors", RUBY_METHOD_FUNC(p4_get_errors) , 0 ); rb_define_method( cP4, "messages", RUBY_METHOD_FUNC(p4_get_messages), 0 ); rb_define_method( cP4, "warnings", RUBY_METHOD_FUNC(p4_get_warnings), 0 ); rb_define_method( cP4, "exception_level", RUBY_METHOD_FUNC(p4_get_except_level), 0 ); rb_define_method( cP4, "exception_level=", RUBY_METHOD_FUNC(p4_set_except_level), 1 ); rb_define_method( cP4, "server_level", RUBY_METHOD_FUNC(p4_get_server_level), 0 ); rb_define_method( cP4, "server_case_sensitive?", RUBY_METHOD_FUNC(p4_server_case_sensitive), 0 ); rb_define_method( cP4, "track_output", RUBY_METHOD_FUNC(p4_track_output), 0 ); rb_define_method( cP4, "server_unicode?", RUBY_METHOD_FUNC(p4_server_unicode), 0 ); // Spec parsing rb_define_method( cP4, "parse_spec", RUBY_METHOD_FUNC(p4_parse_spec), 2 ); rb_define_method( cP4, "format_spec", RUBY_METHOD_FUNC(p4_format_spec), 2 ); // Identification rb_define_const( cP4, "P4API_VERSION", P4Utils::ruby_string(P4APIVER_STRING)); rb_define_const( cP4, "P4API_PATCHLEVEL", INT2NUM(P4API_PATCHLEVEL)); rb_define_const( cP4, "P4RUBY_VERSION", P4Utils::ruby_string(P4RUBY_VERSION) ); rb_define_singleton_method( cP4, "identify", RUBY_METHOD_FUNC(p4_identify), 0 ); // Debugging support rb_define_method( cP4, "debug", RUBY_METHOD_FUNC(p4_get_debug), 0); rb_define_method( cP4, "debug=", RUBY_METHOD_FUNC(p4_set_debug), 1 ); // Support for OutputHandler rb_define_method( cP4, "handler", RUBY_METHOD_FUNC(p4_get_handler), 0); rb_define_method( cP4, "handler=", RUBY_METHOD_FUNC(p4_set_handler), 1); // Support for Progress API rb_define_method( cP4, "progress", RUBY_METHOD_FUNC(p4_get_progress), 0); rb_define_method( cP4, "progress=", RUBY_METHOD_FUNC(p4_set_progress), 1); // P4::MergeData class cP4MD = rb_define_class_under( cP4, "MergeData", rb_cObject ); rb_define_method( cP4MD, "your_name", RUBY_METHOD_FUNC(p4md_getyourname),0); rb_define_method( cP4MD, "their_name", RUBY_METHOD_FUNC(p4md_gettheirname),0); rb_define_method( cP4MD, "base_name", RUBY_METHOD_FUNC(p4md_getbasename),0); rb_define_method( cP4MD, "your_path", RUBY_METHOD_FUNC(p4md_getyourpath),0); rb_define_method( cP4MD, "their_path", RUBY_METHOD_FUNC(p4md_gettheirpath),0); rb_define_method( cP4MD, "base_path", RUBY_METHOD_FUNC(p4md_getbasepath),0); rb_define_method( cP4MD, "result_path", RUBY_METHOD_FUNC(p4md_getresultpath),0); rb_define_method( cP4MD, "merge_hint", RUBY_METHOD_FUNC(p4md_getmergehint),0); rb_define_method( cP4MD, "run_merge", RUBY_METHOD_FUNC(p4md_runmerge),0); rb_define_method(cP4MD, "action_resolve?", RUBY_METHOD_FUNC(p4md_getactionresolve), 0); rb_define_method(cP4MD, "action_type", RUBY_METHOD_FUNC(p4md_getactiontype), 0); rb_define_method(cP4MD, "content_resolve?", RUBY_METHOD_FUNC(p4md_getcontentresolve), 0); rb_define_method(cP4MD, "info", RUBY_METHOD_FUNC(p4md_getinfo), 0); rb_define_method(cP4MD, "invalidate", RUBY_METHOD_FUNC(p4md_invalidate), 0); rb_define_method(cP4MD, "merge_action", RUBY_METHOD_FUNC(p4md_getmergeaction), 0); rb_define_method(cP4MD, "their_action", RUBY_METHOD_FUNC(p4md_gettheiraction), 0); rb_define_method(cP4MD, "to_s", RUBY_METHOD_FUNC(p4md_tos), 0); rb_define_method(cP4MD, "yours_action", RUBY_METHOD_FUNC(p4md_getyoursaction), 0); // P4::Map class cP4Map = rb_define_class_under( cP4, "Map", rb_cObject ); rb_define_singleton_method( cP4Map, "new", RUBY_METHOD_FUNC(p4map_new), -1); rb_define_singleton_method( cP4Map, "join", RUBY_METHOD_FUNC(p4map_join), 2 ); rb_define_method( cP4Map, "insert", RUBY_METHOD_FUNC(p4map_insert),-1); rb_define_method( cP4Map, "inspect", RUBY_METHOD_FUNC(p4map_inspect),0); rb_define_method( cP4Map, "clear", RUBY_METHOD_FUNC(p4map_clear),0); rb_define_method( cP4Map, "count", RUBY_METHOD_FUNC(p4map_count),0); rb_define_method( cP4Map, "empty?", RUBY_METHOD_FUNC(p4map_empty),0); rb_define_method( cP4Map, "translate", RUBY_METHOD_FUNC(p4map_trans),-1); rb_define_method( cP4Map, "reverse", RUBY_METHOD_FUNC(p4map_reverse),0); rb_define_method( cP4Map, "includes?", RUBY_METHOD_FUNC(p4map_includes),1); rb_define_method( cP4Map, "lhs", RUBY_METHOD_FUNC(p4map_lhs),0); rb_define_method( cP4Map, "rhs", RUBY_METHOD_FUNC(p4map_rhs),0); rb_define_method( cP4Map, "to_a", RUBY_METHOD_FUNC(p4map_to_a),0); // P4::Message class. cP4Msg = rb_define_class_under( cP4, "Message", rb_cObject ); rb_define_method( cP4Msg, "inspect", RUBY_METHOD_FUNC(p4msg_inspect),0); rb_define_method( cP4Msg, "msgid", RUBY_METHOD_FUNC(p4msg_get_id), 0); rb_define_method( cP4Msg, "severity", RUBY_METHOD_FUNC(p4msg_get_severity), 0); rb_define_method( cP4Msg, "generic", RUBY_METHOD_FUNC(p4msg_get_generic), 0); rb_define_method( cP4Msg, "to_s", RUBY_METHOD_FUNC(p4msg_get_text), 0); // P4::Progress class. cP4Prog = rb_define_class_under( cP4, "Progress", rb_cObject ); }; } // Extern C
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 14694 | tjuricek |
Add `enviro_file` property to `P4` object that calls SetEnviroFile and GetEnviroFile underneath. P4RUBY-169 Imported from Git Author: Tristan Juricek <tjuricek@perforce.com> 1418331105 -0800 Committer: Tristan Juricek <tjuricek@perforce.com> 1418331105 -0800 sha1: 141f8b9f65b4c56ce5a42144d8c185285effaa12 push-state: complete parent-changes: 98f9b10c0c37b44bfc8659e7934440fe1252c4c2=[974326] |
||
#1 | 14682 | Git Fusion |
Git Fusion branch management Imported from Git ghost-of-change-num: 960958 ghost-of-sha1: 005052ae424bd69f426f7209e741ca1c8c3253c7 ghost-precedes-sha1: ad052c71a568ef12165e143a6866ad9ceffbb4a1 parent-branch: None@960958 push-state: incomplete |