/* * Copyright 1995, 1996 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ # include <stdhdrs.h> # include <strbuf.h> # include <strops.h> # include <enviro.h> # include <error.h> # include <strarray.h> # include <strdict.h> # include <strtable.h> # include <spec.h> # include <options.h> # include <filesys.h> # include "clientuser.h" # include "clientuserdbg.h" /* * ClientUserDebug -- version of output that always to stdout */ void ClientUserDebug::OutputError( const char *errBuf ) { OutputTag( "error", errBuf, strlen( errBuf ) ); } void ClientUserDebug::OutputInfo( char level, const char *data ) { switch( level ) { default: OutputTag( "info", data, strlen( data ) ); break; case '1': OutputTag( "info1", data, strlen( data ) ); break; case '2': OutputTag( "info2", data, strlen( data ) ); break; } } void ClientUserDebug::OutputText( const char *data, int length ) { OutputTag( "text", data, length ); } void ClientUserDebug::OutputTag( const char *tag, const char *data, int length ) { char *p; while( p = (char *)memchr( data, '\n', length ) ) { printf( "%s: ", tag ); fwrite( data, 1, p + 1 - data, stdout ); length -= p + 1 - data; data = p + 1; } if( length ) { printf( "%s: ", tag ); fwrite( data, 1, length, stdout ); printf( "\n" ); } } /* * ClientUserDebugMsg -- message debugging ("-e" global opt) */ void ClientUserDebugMsg::Message( Error *err ) { ClientUserDebug::Message( err ); // print error subcodes for each ErrorId ErrorId* id; for ( int i = 0 ; id = err->GetId( i ) ; i++ ) printf( "code%d %d (sub %d sys %d gen %d args %d sev %d uniq %d)\n", i, id->code, id->SubCode(), id->Subsystem(), id->Generic(), id->ArgCount(), id->Severity(), id->UniqueCode() ); // use base ClientUser OutputStat/Info() to print dict ClientUser ui; if ( err->GetDict() ) ui.OutputStat( err->GetDict() ); } /* * ClientUserFmt -- user-specified formatting ("-F" global opt) */ void ClientUserFmt::Message( Error *err ) { OutputStat( err->GetDict() ); } void ClientUserFmt::OutputStat( StrDict *dict ) { if( !dict ) return; StrBuf out; StrOps::Expand2( out, *fmt, *dict ); if( out.Length() ) printf( "%s\n", out.Text() ); } /* * ClientUserMunge -- user-specified munging ("--field" global opt) */ ClientUserMunge::ClientUserMunge( Options &opts ) { // Get the list of field substitutions from the Options. const StrPtr *s; for( int i = 0 ; s = opts.GetValue( Options::Field, i ) ; i++ ) fields.Put( *s ); } void ClientUserMunge::OutputStat( StrDict *dict ) { Munge( dict, &fields, this ); } void ClientUserMunge::Munge( StrDict *dict, StrPtrArray *fields, ClientUser *ui ) { StrPtr *specdef = dict->GetVar( "specdef" ); if( !specdef ) return ui->OutputError( "This command did not return a spec." " Try 'p4 (spectype) -o'?\n" ); Error e; // Build the spec. Spec spec( specdef->Text(), "", &e ); if( e.Test() ) return ui->HandleError( &e ); // Copy and modify the dict. StrBufDict d( *dict ); StrBuf field, value; for( int i = 0 ; i < fields->Count() ; i++ ) { const StrPtr *s = fields->Get( i ); int plus = 0; const char *eq = s->Contains( StrRef( "=" ) ); if( !eq || eq == s->Text() ) return ui->OutputError( "Usage: --field Field=value\n" ); field.Set( s->Text(), eq - s->Text() ); if( field.Text()[ field.Length() - 1 ] == '+' ) { plus = 1; field.SetLength( field.Length() - 1 ); } field.Terminate(); SpecElem *elem = spec.Find( field, &e ); if( !elem ) return ui->HandleError( &e ); value.Clear(); int x = 0; if( plus && !elem->IsList() ) { // Single entry, get existing. if( d.GetVar( field ) ) value.Append( d.GetVar( field ) ); } if( elem->IsList() ) { // List entry, get index for last item. for( int j = 0 ; d.GetVar( field, j ) ; j++ ) x = j + 1; } if( x && !plus ) { // Go back and remove existing list items. StrBuf fn; StrNum y; while( x ) { x--; fn = field; y = x; fn.Append( y.Text() ); d.RemoveVar( fn ); } } value.Append( eq + 1 ); if( elem->IsList() ) d.SetVar( field, x, value ); else d.ReplaceVar( field, value ); } // Format spec. SpecDataTable data( &d ); StrBuf result; spec.Format( &data, &result ); ui->OutputText( result.Text(), result.Length() ); }