clientusermsh.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2016-1/
  • client/
  • clientusermsh.cc
  • View
  • Commits
  • Open Download .zip Download (25 KB)
/*
 * Copyright 1995, 2000 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

/*
 * ClientUserMarshal - Classes for doing ClientUser I/O as 
 *		       marshalled data for scripting languages.
 */


# define NEED_FILE

# ifdef OS_NT
# define NEED_FCNTL
# endif

# include <stdhdrs.h>

# include <strbuf.h>
# include <strops.h>
# include <strdict.h>
# include <strtable.h>
# include <enviro.h>
# include <error.h>

# include <signaler.h>
# include <filesys.h>
# include <diff.h>

# include <spec.h>
# include <msgclient.h>
# include <p4tags.h>

# include "clientuser.h"
# include "clientusermsh.h"

# ifdef OS_SCO
# define INLINE /**/
# else
# define INLINE inline
# endif

/*******************************************************************************
 * Local class definitions
 ******************************************************************************/

/*
 * MarshalDict : a StrBuf that holds a marshalled Dictionary Object
 *
 * Virtual base class for language specific marshalling. 
 */
class MarshalDict : public StrBuf
{
    public:

	virtual		~MarshalDict();

	// Read/Write

	virtual void	StartWrite( const char *code ) = 0;
	virtual void	EndWrite() = 0;

	virtual void	StartRead( Error *e ) = 0;
	virtual void	EndRead( Error *e ) = 0;

	// Writing dictionary pairs

	void		Add( const char *code, const StrPtr &value )
			{ AddString( StrRef( code ) ); AddString( value ); }

	void		Add( const StrPtr &code, const StrPtr &value )
			{ AddString( code ); AddString( value ); }

	void		Add( const char *code, int value )
			{ AddString( StrRef( code ) ); AddInt( value ); }


	// Reading dictionary pairs

	virtual int Get( StrBuf &var, StrBuf &val ) = 0;

    protected:

	// Low level string/int/etc

	virtual void	AddInt( int value ) = 0;
	virtual void	AddString( const StrPtr &value ) = 0;

	void		AddCode( char c )
			{ Extend( c ); }

	INLINE int	GetChar( char c );

	StrRef		s;	// StrRef access to the buffer


} ;

/*
 * PythonDict : a MarshalDict that holds a marshalled Python Dictionary Object
 *
 * This class either reads or writes (from stdin/stdout) a Python
 * dictionary object in Python's "marshalling" format.
 *
 * PythonDict will write the object if the constructor is given a
 * "code" value, which will appear in the dictionary as "code" : code.
 */

class PythonDict : public MarshalDict
{
    public:

	// Read/Write

	void		StartWrite( const char *code );
	void		EndWrite();

	void		StartRead( Error *e );
	void		EndRead( Error *e );


	// Reading dictionary pairs

	INLINE int	Get( StrBuf &var, StrBuf &val );

    protected:

	// Low level string/int/etc

	void		AddInt( int value )
			{ AddCode( 'i' ); StrOps::PackInt( *this, value ); }

	void		AddString( const StrPtr &value )
			{ AddCode( 's' ); StrOps::PackString( *this, value ); }

} ;

/*
 * RubyDict : a MarshalDict that holds a marshalled Ruby Hash Object
 *
 * This class either reads or writes (from stdin/stdout) a Ruby
 * hash object in Ruby's "marshalled" format.  This differs from the
 * Python version in that Ruby marshalled objects have their length at
 * the beginning so we have to save the actual write till the end when
 * we know what the length should be.
 *
 */


/*
 * Minimum Ruby marshalling format supported. If the major number of any
 * input matches, we'll try and read it even if the minor number differs.
 * For output, we'll always use this version.
 */
#define RUBY_SUPPORTED_MAJOR		4
#define RUBY_SUPPORTED_MINOR		6

/*
 * Some macros to help with version handling
 */
#define RUBY_VERSION( maj, min )	( (maj << 8) | min  )
#define RUBY_MAJOR( ver )		( (ver >> 8) & 0x0f )
#define RUBY_MINOR( ver )		( ver & 0x0f )

class RubyDict : public MarshalDict
{
    public:

	// Read/Write

	void		StartWrite( const char *code );
	void		EndWrite();

	void		StartRead( Error *e );
	void		EndRead( Error *e );


	// Reading dictionary pairs

	INLINE int	Get( StrBuf &var, StrBuf &val );

    private:

	// Low level string/int/etc to implement MarshalDict interface

	void		AddInt( int value );
	void		AddString( const StrPtr &value );

	// Class Methods supporting Ruby Marshalled format

	static void	PackInt(   StrBuf &dict, int value );
	static int	UnpackInt( StrRef &str );
	static void	UnpackString( StrRef &str, StrBuf &buf );
	static int	UnpackVersion( StrRef &str );

    private:
	int		elemCount;	// Number of elements in the hash

} ;


/*
 * PhpDict : a MarshalDict that holds a serialized PHP array.
 *
 * This class either reads or writes (from stdin/stdout) an array
 * in Serialized PHP format.
 */
class PhpDict : public MarshalDict
{
    public:

    // Read/Write

    void        StartWrite( const char *code );
    void        EndWrite();

    void        StartRead( Error *e );
    void        EndRead( Error *e );


    // Reading dictionary pairs

    INLINE int  Get( StrBuf &var, StrBuf &val );

    protected:

    // Low level string/int/etc to implement MarshalDict interface

    void        AddInt( int value );
    void        AddString( const StrPtr &value );

    // Class method supporting string de-serialization

    static int  UnpackString( StrRef &str, StrBuf &buf );
    
    private:
    int     elemCount;  // Number of elements in the array

} ;


/*******************************************************************************
 * MarshalDict methods
 ******************************************************************************/

// empty virtual destructor
MarshalDict::~MarshalDict()
{
}

/*
 * Checks whether or not the next char in the input is what is expected.
 * returns 1 if it is, and zero if it's not.
 */

INLINE int
MarshalDict::GetChar( char c ) 
{
	if( !s.Length() || s[0] != c )
	    return 0;
	s.Set( s.Text() + 1, s.Length() - 1 );
	return 1;
}


/*******************************************************************************
 *  PythonDict methods
 ******************************************************************************/

/*
 * Get a variable and value pair from a Marshalled Python dictionary
 * Returns non-zero on success.
 */

INLINE int
PythonDict::Get( StrBuf &var, StrBuf &val )
{
	if( !GetChar('s') && !GetChar('u') )
		// Return if input is neither a string nor an Unicode
		// string (Python 3.x uses Unicode strings by default).
		return 0;

	StrOps::UnpackString( s, var ); // bytes in 'u' strings are always 
	                                // UTF-8 encoded.
	
	if( !GetChar('s') && !GetChar('u') )
		return 0;
	StrOps::UnpackString( s, val );

	return 1;
}

/*
 * Prepare a Python Marhsalled dictionary for writing. Just involves
 * opening the dictionary with a "{" character and writing the "code"
 * member.
 */

void
PythonDict::StartWrite( const char *code ) 
{ 
    	Clear();
	AddCode( '{' );
	Add( "code", StrRef( code ) );
	s.Set( 0, 0 ); 
}

/*
 * Close a marshalled dictionary and write it to stdout.
 */

void
PythonDict::EndWrite() 
{ 
	AddCode( '0' ); 
}

/*
 * Start reading a Python marshalled dictionary. 
 */

void
PythonDict::StartRead( Error *e )
{
    	s.Set( *this );
	if( !GetChar( '{' ) )
	    e->Set( MsgClient::BadMarshalInput );
}

/*
 * Finish off the read of a Python marshalled dictionary. Just involves
 * reading the trailing '0'
 */

void
PythonDict::EndRead( Error *e )
{
	if( !GetChar( '0' ) )
	    e->Set( MsgClient::BadMarshalInput );
}

/*******************************************************************************
 *  RubyDict methods
 ******************************************************************************/

/*
 * Read the next key = value pair from the marshalled hash. When reading
 * the elemcount is the number of pairs so we only decrease it by one.
 */

INLINE int
RubyDict::Get( StrBuf &var, StrBuf &val )
{
    	if( ! elemCount ) return 0;

	if( !GetChar( '"' ) ) return 0;
	UnpackString( s, var );

	if( ! GetChar( '"' ) ) return 0;
	UnpackString( s, val );

	--elemCount;
	return 1;
}

/*
 * Append an integer to the marshalled data in Ruby marshalled format.
 */

void
RubyDict::AddInt( int value )
{
	AddCode( 'i' );
	PackInt( *this, value );
	elemCount++;
}

/*
 * Append a string to the marshalled data in Ruby marshalled format
 */


void 
RubyDict::AddString( const StrPtr &value )
{
	AddCode( '"' );
	PackInt( *this, value.Length() );
	Append( value.Text(), value.Length() );
	elemCount++;
}

/*
 * Initialise the Ruby marshalled hash. We don't write the preamble at
 * this point because we don't know the length of the hash. 
 */

void
RubyDict::StartWrite( const char *code ) 
{ 
    	Clear();
	elemCount = 0;		// No of elements (i.e 1 per key, 1 per value)
	Add( "code", StrRef( code ) );
	s.Set( 0, 0 ); 
}

/*
 * Terminate the hash. Now that we know the number of elements, we can
 * wite out the preamble and the hash data itself.
 */

void
RubyDict::EndWrite() 
{ 
	/*
	 * Because Ruby marshalled hashes contain their length, we can't
	 * write the preamble until we know the number of elements in the
	 * hash. So the string is built without any preamble and we
	 * now have to work out the number of hash pairs from elemCount
	 * and write the preamble accordingly
	 */

    	StrBuf  tmp;
	char *t = tmp.Alloc( 4 );

	t[0] = RUBY_SUPPORTED_MAJOR;
	t[1] = RUBY_SUPPORTED_MINOR;
	t[2] = '{'; 			// Marks the start of a hash
	tmp.SetEnd( t + 3 );

	PackInt( tmp, elemCount / 2 );

	// Append our current contents to the header
	tmp << *this;

	// Copy the final result into our buffer
	Set( tmp );
}


/*
 * Start reading a Ruby marshalled hash. It should be prefixed by
 * the major and minor marshalling numbers to make sure we're using the
 * right version of the marshalling format. 
 */

void
RubyDict::StartRead( Error *e )
{
    	s.Set( *this );

    	int valid = 1;
	int version = UnpackVersion( s );

	if( RUBY_MAJOR( version ) != RUBY_SUPPORTED_MAJOR )
	    valid = 0;

	if( RUBY_MINOR( version ) < RUBY_SUPPORTED_MINOR )
	    valid = 0;

	if( valid )
	    valid = GetChar( '{' );

	if( !valid )
	{
	    e->Set( MsgClient::BadMarshalInput );
	    return;
	}

	// On a read elemCount is the number of *pairs*
	elemCount = UnpackInt( s );
}

/*
 * Read any termination for a Ruby marshalled hash (there is none).
 */
 
void
RubyDict::EndRead( Error *e )
{
	// Nothing to do for Ruby.
	return;
}


/*
 * Pack an integer in Ruby format. This is mostly taken from ruby's marshal.c
 * and is pretty arcane stuff. The basic idea is this:
 *
 * The first byte of a ruby marshalled int tells you (a) whether or not
 * the value is negative and (b) either the number itself or the number of
 * following bytes in which the number is encoded. 
 *
 * Since there will never (ha!) be more than 4 bytes of encoding (marshal.c 
 * does not support marshalling longs - at the moment) Matz has chosen to use
 * this to pack numbers in the range -123 <= x <= 122 in a single byte. i.e.
 * ( -128 + 5 ) <= x <= ( 127 - 5 ).
 *
 * If the first byte is in the range -4 <= x <= 4 then this indicates the
 * number of following bytes in which the rest of the number is marshalled.
 *
 * Negative numbers always have the high bit set in the first byte.
 */

void
RubyDict::PackInt( StrBuf &dict, int value )
{
	/*
	 * 64-bit ints are not supported by Ruby's marshalling code at this 
	 * time (1.6.8) so we assume we're packing a 32-bit int. This also
	 * seems reasonable since Perforce are 32-bit so we should not
	 * need to pack 64-bit ints for some time.
	 */

#define PACKSIZE	4
    	char		buf[ PACKSIZE ];
	int		len = 0;

	if( 0 < value && value < ( 127 - PACKSIZE ) )
	    buf[ len++ ] = value + PACKSIZE + 1;

	else if( value > ( PACKSIZE - 128 ) && value < 0 )
	    buf[ len++ ] = (value - PACKSIZE - 1) & 0xff;

	// If it's packed in a single byte, we're out easy.

	if ( len )
	{
	    dict.Append( buf, len );
	    return;
	}

	// More than one byte required.

	for( len = 1; len < 5; len++ )
	{
	    buf[ len ] = value & 0xff;
	    value = value >> 8;

	    if( value == 0 )
	    {
		buf[ 0 ] = len;
		break;
	    }

	    if( value == -1 )
	    {
		buf[ 0 ] = -len;
		break;
	    }
	}
	dict.Append( buf, len + 1 );
}


/*
 * Unpack an integer packed in Ruby format. See comments on PackInt for
 * a description of the packed format.
 */

int
RubyDict::UnpackInt( StrRef &str )
{
	int		i = 0;
	int		isneg = 0;
	int		len;
	int		value;

	if( ! str.Length() ) return 0;

	value = str[ i++ ];
	str += 1;

	if( value == 0 ) return 0;

	if( 4    < value && value < 128 ) 	return value - 5;
	if( -129 < value && value <  -4 ) 	return value + 5;

	// what we've got so far is just the number of bytes 

	len = value;
	value = 0;

	if( isneg = ( len < 0 ) )
	{
	    len = -len;
	    value = -1;
	}

	// Make sure the buffer is long enough first

	if( str.Length() < len ) return 0;

	for( i = 0; i < len; i++ )
	{
	    if( isneg )
		value &= ~( (long)0xff << ( 8 * i ) );
	    value |= ( ((long)str[i] & 0xff) << ( 8 * i ) );
	}
	
	str += len;
	return value;
}


/*
 * Unpack a string into a buffer. Just a matter of unpacking the length
 * of the string first, then you can just extract the string directly.
 */

void
RubyDict::UnpackString( StrRef &str, StrBuf &buf )
{
	int len = UnpackInt( str );
	if( ! len ) return;

	buf.Set( str.Text(), len );
	str += len;
}

/*
 * Unpack the Ruby marshalling format into an int. This is coded as two
 * bytes at the start of the input. They're not encoded using the normal
 * PackInt()/UnpackInt() code above, just raw.
 */
int
RubyDict::UnpackVersion( StrRef &str )
{
    int major;
    int minor;

    // Must be at least two bytes there.
    if( str.Length() < 2 ) return 0;
    
    major = str[ 0 ];
    minor = str[ 1 ];
    str += 2;

    return RUBY_VERSION( major,  minor );
}

/*******************************************************************************
 *  PhpDict methods
 ******************************************************************************/

/*
 * Begin writing a block of output. Each output block is represented
 * as a serialized PHP array. The first element is always the "code"
 * (or output type).
 *
 * PHP serializes arrays as "a:<n>:{<element>,<element>,...}".
 * Therefore, we defer writing the beginning of the array because
 * we don't know the length. All we write at this point is the "code"
 * element. We will both open and close the array in EndWrite.
 */

void
PhpDict::StartWrite( const char *code )
{
    Clear();
    elemCount = 0;
    Add( "code", StrRef( code ) );
}


/*
 * Append a integer to the current block of output.
 */

void
PhpDict::AddInt( int value )
{
    Append( "i:" );
    *this << value;
    Append( ";" );

    // Bump the element count.
    elemCount++;
}


/*
 * Append a string to the current block of output.
 */

void
PhpDict::AddString( const StrPtr &value )
{
    Append( "s:" );
    *this << value.Length();
    Append( ":\"" );
    Append( &value );
    Append( "\";" );

    // Bump the element count.
    elemCount++;
}


/*
 * Finish writing a block of output. Arrays are closed with "}".
 * Now that we know the number of elements we can properly open
 * the array (which was deferred in StartWrite).
 */

void
PhpDict::EndWrite()
{
    // Open the array.
    StrBuf tmp;
    tmp.Append( "a:" );
    tmp << elemCount / 2;
    tmp.Append( ":{" );
    tmp << *this;
    Set( tmp );

    // Close the array.
    Append( "}" );
}


/*
 * Start reading a serialized PHP array.
 */

void
PhpDict::StartRead( Error *e )
{
    s.Set( *this );

    // Input array begins with 'a:<n>:{'
    // Read to opening bracket
    while ( s.Length() )
    {
        if( GetChar( '{' ) ) return;
        s.Set( s.Text() + 1, s.Length() - 1 );
    }
    e->Set( MsgClient::BadMarshalInput );
}


/*
 * Get a variable and value pair from a serialized PHP array.
 * Returns non-zero on success.
 */

INLINE int
PhpDict::Get( StrBuf &var, StrBuf &val )
{
    if( !GetChar( 's' ) || !UnpackString( s, var ) )
        return 0;

    if( !GetChar( 's' ) || !UnpackString( s, val ) )
        return 0;

    return 1;
}


/*
 * Unpack a PHP serialized string into a buffer. Just a matter of 
 * reading the length of the string first, then we can skip past the
 * delimiters and extract the string directly. Returns non-zero on success.
 */

int
PhpDict::UnpackString( StrRef &str, StrBuf &buf )
{
    // Determine length of string
    StrBuf len;
    str.Set( str.Text() + 1, str.Length() - 1 );
    while ( str[0] != ':' && str.Length() > 0 )
    {
        len.Append( str.Text(), 1 );
        str.Set( str.Text() + 1, str.Length() - 1 );
    }

    // Verify len won't exceed str length
    // Note: strings are wrapped in two characters on either side
    if( str.Length() < len.Atoi() + 4 ) return 0;

    // Extract string to buf and advance str reference
    buf.Set( str.Text() + 2, len.Atoi() );
    str.Set( str.Text() + buf.Length() + 4, str.Length() - buf.Length() - 4 );

    return 1;
}


/*
 * Finish off the read of a serialized PHP array.
 * Just involves reading the trailing '}'
 */

void
PhpDict::EndRead( Error *e )
{
    if( !GetChar( '}' ) )
        e->Set( MsgClient::BadMarshalInput );
}


/*******************************************************************************
 *  ClientUserMarshal methods
 ******************************************************************************/

/*
 * Constructor. 
 */

ClientUserMarshal::ClientUserMarshal()
{
# ifdef OS_NT
	// both python and ruby marshalled formats are binary

        setmode( fileno( stdin ), O_BINARY );
        setmode( fileno( stdout ), O_BINARY );
# endif
	result = NULL;
}

/*
 * Destructor.
 */

ClientUserMarshal::~ClientUserMarshal()
{
	if( result ) delete result;
}

/*
 * Write any errors into the output dictionary/hash
 */

void
ClientUserMarshal::HandleError( Error *err )
{
	StrBuf msg;
	err->Fmt( msg, EF_NEWLINE );

	result->StartWrite( "error" );
	result->Add( "data", msg );
	result->Add( "severity", err->GetSeverity() );
	result->Add( "generic", err->GetGeneric() );
	result->EndWrite();
	WriteOutput( result );
}

/*
 * Write text errors into the output
 */

void
ClientUserMarshal::OutputError( const char *errBuf )
{
	result->StartWrite( "error" );
	result->Add( "data", StrRef( errBuf ) );
	result->EndWrite();
	WriteOutput( result );
}

/*
 * Write text output with level indicator into the output
 */

void
ClientUserMarshal::OutputInfo( char level, const char *data )
{
	result->StartWrite( "info" );
	result->Add( "level", level - '0' );
	result->Add( "data", StrRef( data ) );
	result->EndWrite();
	WriteOutput( result );
}

/*
 * Write plain text output.
 */

void
ClientUserMarshal::OutputText( const char *data, int length )
{
	result->StartWrite( "text" );
	result->Add( "data", StrRef( data, length ) );
	result->EndWrite();
	WriteOutput( result );
}

/*
 * Write binary output into the hash. The binary data is just 
 * encoded as a string.
 */

void
ClientUserMarshal::OutputBinary( const char *data, int length )
{
	result->StartWrite( "binary" );
	result->Add( P4Tag::v_data, StrRef( data, length ) );
	result->EndWrite();
	WriteOutput( result );
}

/*
 * Tagged output support. If we have both a data and specdef members of
 * the StrDict, then we try to parse the form directly into a StrDict and
 * add that to the output rather than the enclosing StrDict. 
 */

void
ClientUserMarshal::OutputStat( StrDict *varList )
{
	SpecDataTable specData;

	StrPtr *data = varList->GetVar( P4Tag::v_data );
	StrPtr *spec = varList->GetVar( P4Tag::v_specdef );
	StrPtr *specFormatted = varList->GetVar( P4Tag::v_specFormatted );
	StrDict *dict = varList;

	/*
	 *  Normally, we scan the ClientUser::varList and
	 *  add variable into the python dictionary object.
	 *  But if we're dealing with form output, let's go
	 *  ahead and try to parse the form.
	 */

	if( spec && data )
	{
	    
	    /*
	     * Parse the form data using the spec,
	     * and load the result into the SpecDataTable.
	     * That stores its contents in a StrDict.
	     * Use that for our results.
	     */

	     Error e;
	     Spec s( spec->Text(), "", &e );
	     if( !e.Test() ) 
	     	s.ParseNoValid( data->Text(), &specData, &e );

	     if( e.Test() ) 
	     {
		 HandleError( &e );
		 return;
	     }

	     dict = specData.Dict();
	}

	result->StartWrite( P4Tag::v_stat );

	// Don't put in the 'func' (that's for us).
	// Don't put in 'specFormatted' (tagged forms are formatted 
	// by the server in 5.2).
	// Don't put in 'specdef' unless this is not spec data formatted 
	// by the server. 'p4 jobs -G' needs specdef to be set.


	int i;
	StrRef var, val;

	for( i = 0; dict->GetVar( i, var, val ); i++ )
	    if( var != P4Tag::v_func && var != P4Tag::v_specFormatted &&
	      ( var != P4Tag::v_specdef || !specFormatted ) )
		result->Add( var, val );

	result->EndWrite();
	WriteOutput( result );
}

/*
 * Diff output support. Extends parent to collect output in a temp file
 * so that it can be routed through OutputText() and serialized.
 */

void
ClientUserMarshal::Diff( FileSys *f1, FileSys *f2, int doPage, char *df, Error *e )
{
	// Create temp file to collect output.
	FileSys *t = File( FileSysType( ( f1->GetType() & FST_L_MASK )
				| FST_UNICODE ) );
	t->MakeGlobalTemp();

	// Perform diff
	ClientUser::Diff(f1, f2, t, doPage, df, e);

	// Stream diffs to OutputText()
	t->Open( FOM_READ, e );
	if( !e->Test() )
	{
	    char buf[4096];
	    int i;

	    while( (i = t->Read( buf, sizeof(buf), e )) > 0
		&& !e->Test() )
		OutputText( buf, i );

	    t->Close( e );
	}
	t->Unlink( e );

	delete t;
}

/*
 * Input -- parse a marshalled object!
 */

void
ClientUserMarshal::InputData( StrBuf *buf, Error *e )
{
	/*
	 * If no spec, we'll just pass to ClientUser.
	 * A sorry default, but only forms related commands 
	 * use InputData.
	 */

	StrPtr *spec = varList->GetVar( P4Tag::v_specdef );

	if( !spec )
	{
	    ClientUser::InputData( buf, e );
	    return;
	}

	/*
	 * We've got a spec form: read the dictionary
	 * entry from stdin and format it using the spec.
	 */

	StrBuf var, val;
	SpecDataTable specData;

	/*
	 * Load the input from the user
	 */
	ReadInput( result, e );

	/* Read dictionary entries */
	/* and put them into our table. */

	result->StartRead( e );
	while( result->Get( var, val ) )
	    specData.Dict()->SetVar( var, val );
	result->EndRead( e );

	/*
	 * Errors here are not fatal to the client, but they
	 * need to be reported. 
	 */
	if( e->Test() )
	{
	    HandleError( e );
	    e->Clear();
	    return;
	}
	    
	/* Using our table and the spec, */
	/* format and return the form. */

	Spec s( spec->Text(), "", e );
	if( e->Test() )
	{
	    HandleError( e );
	    e->Clear();
	    return;
	}

	s.Format( &specData, buf );

}

// 
// Read input from stdin and load it into a buffer
//
void
ClientUserMarshal::ReadInput( StrBuf *buf, Error *e )
{
	int n;
	int size = FileSys::BufferSize();

	do {
	    char *b = buf->Alloc( size );
	    n = read( 0, b, size );
	    if( n < 0 )
	    {
		e->Sys( "read", "stdin" );
		break;
	    }
	    buf->SetEnd( b + n );
	} while( n > 0 );

}

//
// Write the result buffer to stdout. Subclasses can override to 
// redirect the output elsewhere
//
void
ClientUserMarshal::WriteOutput( StrPtr *buf )
{
    	fwrite( buf->Text(), 1, buf->Length(), stdout );
}

/*******************************************************************************
 *  ClientUserPython methods
 ******************************************************************************/

/*
 * ClientUserPython - ClientUser I/O is marshalled Python data
 * 
 * Just ClientUserMarshal but with a Python dictionary.
 */

ClientUserPython::ClientUserPython()
{
	result = new PythonDict;
}

/*******************************************************************************
 *  ClientUserRuby methods
 ******************************************************************************/

/*
 * ClientUserRuby - ClientUser I/O is marshalled Ruby data
 * 
 * Just ClientUserMarshal but with a Ruby dictionary.
 */

ClientUserRuby::ClientUserRuby()
{
	result = new RubyDict;
}


/*******************************************************************************
 *  ClientUserPhp methods
 ******************************************************************************/

/*
 * ClientUserPhp - ClientUser I/O is serialized PHP data
 *
 * Differs from other ClientUserMarshal classes in that all
 * output is buffered until the ClientUser object is destroyed.
 */

ClientUserPhp::ClientUserPhp()
{
	result 		 = new PhpDict;
	outputBuffer = new StrBuf;
	outputCount  = 0;
}

ClientUserPhp::~ClientUserPhp()
{
	// Now that all output has been collected, wrap it
	// in an array and write it to stdout
	StrBuf output;
	output.Append( "a:" );
	output << outputCount;
	output.Append( ":{" );
	output.Append( outputBuffer );
	output.Append( "}" );
	fwrite( output.Text(), 1, output.Length(), stdout );
	delete outputBuffer;
}


/*
 * Buffer all output. Output blocks are encapsulated in an array the
 * size of which cannot be known until ClientUser is deconstructed.
 */

void
ClientUserPhp::WriteOutput( StrPtr *buf )
{
	outputBuffer->Append( "i:" );
	*outputBuffer << outputCount;
	outputBuffer->Append( ";" );
	outputBuffer->Append( buf );
	outputCount++;
}

/*
 * ClientUser::Prompt() - don't prompt the user, just collect the response.
 */

void
ClientUserPhp::Prompt( const StrPtr &msg, StrBuf &buf, int noEcho, Error *e )
{
    ClientUser::Prompt( msg, buf, noEcho, 1, e );
}
# Change User Description Committed
#1 19472 Liz Lam Initial add of the 2016.1 p4/p4api source code.