Application Programming
Compiling and linking Perforce applications
The following sections tell you how to build your application on the target platform.
To build p4api.cc
, include
clientapi.h
, which includes all the necessary
header files for the sample client application.
Link order
The link libraries distributed with P4API must be linked explicitly in the following order.
-
libclient.a
-
librpc.a
-
libsupp.a
-
libp4sslstub.a
In the Windows distribution, these files are named
libclient.lib
,
librpc.lib
, libsupp.lib
,
and libp4sslstub.lib
respectively.
SSL support
The Perforce C/C++ API can be configured to support encrypted
connections to the Perforce servers. To enable this support you
must replace the bundled libp4sslstub.a
(on
Windows, libp4sslstub.lib
) with copies of the
OpenSSL libraries. (If you do not intend to use your application
with a Perforce Server that supports encryption then you may simply
compile the application with the supplied stub library.)
OpenSSL libraries are available from many sources; the most up-to-date is from http://www.openssl.org/.
OpenSSL Library Version
We recommend keeping current with the latest minor version
matching the version referenced in the Perforce C/C++ API file
librpc.a
(or librpc.lib
on
Windows). To see which version is referenced by the library, run the
following command on UNIX variants or Macintosh:
strings librpc.a | grep ^OpenSSL
On Windows:
strings librpc.lib | findstr /B OpenSSL
This command will produce an output similar to the following:
OpenSSL 1.0.1g 7 Apr 2014
In this example, you would use the latest minor version of OpenSSL that matches version 1.0.1.
Link order for SSL support
To enable SSL support, replace the stub with the ssl and crypto libraries from openSSL, resulting in the following link order:
-
libclient.a
-
librpc.a
-
libsupp.a
-
libssl.a
-
libcrypto.a
On Windows, the ssl and crypto OpenSSL libraries are named
ssleay32.lib
and
libeay32.lib
respectively.
Compiler support
UNIX
For all UNIX platforms, you can use the gcc compiler to compile client applications with the Perforce C/C++ API. On Solaris, you can also use the Forte compiler.
Note that clientapi.h
includes
stdhdrs.h
, which might attempt to set
platform-specific defines. To ensure these defines are set
properly, compile with the
-DOS_
flag,
where XXX
XXX
is the platform name as
specified by Perforce. (Use p4 -V to display
the platform name; for example, for
LINUX52X86
, specify
-DOS_LINUX
.)
Some platforms require extra link libraries for sockets. Solaris requires the following compiler flags:
-lsocket
-lnsl
Linux
Some platforms require extra link libraries for runtime support. Linux requires the following compiler flag:
-lrt
Windows
Using Microsoft Visual Studio (VC++), compile your client application with the following flags:
/DOS_NT
/MT
/DCASE_INSENSITIVE
For debugging, compile with the /MTd
flag
for multithreading. Do not compile with
/MD
or /MDd
,
because these flags can cause undefined behavior.
Link with the following libraries:
-
libcmt.lib
-
oldnames.lib
-
kernel32.lib
-
ws2_32.lib
-
advapi32.lib
Macintosh
To create an MPW tool, link with the following libraries:
-
Interfacelib
-
PPCToolLibs.o
-
PLStringFuncsPPC.lib
-
MSL-MPWCRuntime.lib
-
MSL-C.PPC-MPW(NL).Lib
-
MSL-C++.PPC.Lib
-
ThreadsLib
-
Mathlib
-
InternetConfigLib
-
OpenTransportLib
-
OpenTptInternetLib
-
OpenTransportAppPPC.o
The compiler option Enums Always Int
must be
on.
VMS
Link with sys$library:libcxxstd.olb/lib
.
Sample Jamfile
The following example shows a Jamfile that can be used to build
p4api.cc
, a Perforce application. (The example
that the API is installed in the api
subdirectory.)
C++FLAGS = -g -D_GNU_SOURCE ; LINK = c++ ;OPTIM = ; Main p4api : p4api.cc ; ObjectHdrs p4api : api ; LinkLibraries p4api : api/libclient.a api/librpc.a api/libsupp.a api/libp4sslstub.a;
For more about jam, see Building with Jam.
Sample Makefile
The following is a gnumake file for building
p4api.cc
, a Perforce application. (The example
assumes the API is installed in the api
subdirectory.)
SOURCES = p4api.cc INCLUDES = -Iapi OBJECTS = ${SOURCES:.cc=.o} LIBRARIES = api/libclient.a api/librpc.a api/libsupp.a api/libp4sslstub.a BINARY = p4api RM = /bin/rm -f C++ = c++ C++FLAGS = -c -g -D_GNU_SOURCE LINK = c++ LINKFLAGS = .cc.o : ${C++} ${C++FLAGS} $< ${INCLUDES} ${BINARY} : ${OBJECTS} ${LINK} -o ${BINARY} ${OBJECTS} ${LIBRARIES} clean : - ${RM} ${OBJECTS} ${BINARY}
Building with Jam
Jam is a build tool, similar in its role to the more familiar make. Jamfiles are to jam as makefiles are to make.
Jam is an Open Source project sponsored by Perforce Software. Jam documentation, source code, and links to precompiled binaries are available from the Jam product information page at:
http://www.perforce.com/documentation/jam
The P4API distribution contains the necessary header files
(*.h
) and libraries
(libclient.a
, librpc.a
,
libsupp.a
, libp4sslstub.a
)
required to compile and link a client application. The distribution
also includes a sample application in C++,
p4api.cc
.
In general, the process is similar to most APIs: compile your application sources, then link them with the API libraries. The precise steps needed vary somewhat from platform to platform.
The sample application p4api.cc
is a portable,
minimal Perforce application, which we can use as an example. For
purposes of this example, assume a Linux system.
Compile and link p4api.cc
as follows:
$ cc -c -o p4api.o -D_GNU_SOURCE -O2 -DOS_LINUX -DOS_LINUX24 \ > -DOS_LINUXX86 -DOS_LINUX24X86 -I. -Imsgs -Isupport -Isys p4api.cc $ gcc -o p4api p4api.o libclient.a librpc.a libsupp.a libp4sslstub.a
The preprocessor definitions
(-D
definition
) vary
from platform to platform.
In order to build the example across a wide variety of platforms, the
API distribution also contains two "Jamfiles"
(Jamrules
and Jamfile
),
that describe to how to build the sample application on each
platform.
Building the sample application
Once you have Jam on your system, you can use it to build the
p4api application. On some platforms,
jam needs an extra hint about the operating
system version. For instance, on RedHat Linux 7.1, with a 2.4 linux
kernel, use OSVER=24
:
$ jam Set OSVER to 42/52 [RedHat M.n], or 22/24 [uname -r M.n] $ uname -r 2.4.2-2 $ jam -s OSVER=24 ...found 121 target(s)... ...updating 2 target(s)... C++ p4api.o Link p4api Chmod1 p4api ...updated 2 target(s)... $ p4api info User name: you Client name: you:home:sunflower Client host: sunflower Client root: /home/you Current directory: /home/you/tmp/p4api Client address: 207.46.230.220:35012 Server address: sunflower:1674 Server root: /home/p4/root Server date: 2009/09/24 12:15:39 PDT Server version: P4D/LINUX22X86/2009.1/192489 (2009/04/12) Server license: Your Company 10 users (expires 2010/02/10) Server license-ip: 10.0.0.2
As shown in the example above, jam does not, by
default, show the actual commands used in the build (unless one of
them fails). To see the exact commands jam
generates, use the -o
file
option. This causes
jam to write the updating actions to
file
, suitable for execution by a shell.
To illustrate; first, invoke jam clean to undo the build:
$ jam -s OSVER=42 clean ...found 1 target(s)... ...updating 1 target(s)... Clean clean ...updated 1 target(s)...
Then use jam -o build_sample to create the build file:
$ jam -s OSVER=42 -o build_sample ...found 121 target(s)... ...updating 2 target(s)... C++ p4api.o Link p4api Chmod1 p4api ...updated 2 target(s)... $ cat build_sample cc -c -o p4api.o -O2 -DOS_LINUX -DOS_LINUX42 -DOS_LINUXX86 \ -DOS_LINUX42X86 -I. -Imsgs -Isupport -Isys p4api.cc gcc -o p4api p4api.o libclient.a librpc.a libsupp.a libp4sslstub.a chmod 711 p4api
The generated build_sample
can then be
executed by a shell:
/bin/sh build_sample
to produce the executable, which you can test by running p4api info or most other Perforce commands:
$ p4api changes -m 1 Change 372 on 2002/09/23 by you@you:home:sunflower 'Building API'
As you can see, p4api is a usable full-featured
command line Perforce client (very similar to the
p4 command). The example's functionality comes
from the default implementation of the
ClientUser
class, linked from the
libclient.a
library and the rest of the
library code, for which source code is not included. The source for
the default implementation is provided in the P4API distribution as
clientuser.cc
.
Sending commands to the versioning service
Perforce applications interact with the versioning service by:
-
Initializing a connection.
-
Sending commands.
-
Closing the connection.
The Perforce server does not maintain any kind of session identifier. The server identifies the sender of commands by its combination of Perforce user name and client workspace. Different processes that use the same combination of user and workspace are not distinguished by the Perforce server. To prevent processes from interfering with each other when submitting changelists, be sure to use separate client specifications for each process. If you need to create large numbers of processes, consider creating a cache of client specifications and serving them to processes as required.
Perforce settings on the user's machine
To determine which server and depot are accessed and how files are mapped, the standard classes in the API observe the Perforce settings on the user's machine. Assuming the workstation is configured correctly, your application does not need to provide logic that specifies server, port, workspace, or user.
To override the user's settings, your application can call
Set
methods.
Settings take precedence as follows, highest to lowest:
-
Values set within a Perforce application
-
Values in configuration files (
P4CONFIG
) -
Values set as environment variables at the operating system prompt
-
Variables residing in the registry (set using the p4 set or p4 set -s commands on Windows client machines)
-
Default values defined by Perforce software or gathered from the system
Connecting to the server
To connect to the Perforce server for which the client computer is
configured, your client application must call the
client.Init()
method; for example:
client.Init( &e ); if ( e.Test() ) { printf("Failed to connect:\n" ); ErrorLog::Abort(); // Displays the error and exits } printf( "Connected OK\n" );
Your program only needs to connect once. After connecting, the
application can issue as many Perforce commands as required. If you
intend to use tagged output, your program must call
client.SetProtocol()
before calling
client.Init()
.
For details about using tagged output, refer to
Tagged data.
Displaying Perforce forms
Perforce client commands that collect a large amount of input from
the user (such as p4 branch, p4
change, p4 label) use ASCII forms. To
interact with your end user, your client application program can
display Perforce ASCII forms such as changelists, client
specification, and so on. To display a form and collect user input,
call
ClientUser::Edit()
,
which puts the form into a temporary file and invokes the text
editor that is configured for the client machine.
All form-related commands accept the batch mode flags
-o
and -i
:
-
-o
causes the form to be passed toClientUser::OutputInfo()
. -
-i
causes the form to be read withClientUser::InputData()
.
These flags allow changes to the form to occur between separate
invocations of the p4 application, rather than
during a single invocation. (For details about the
-o
and -i
global
options, see the
P4
Command Reference.)
All form-related commands can return a form descriptor. Your
application can use this descriptor to parse forms into constituent
variables and to format them from their constituent variables. The
specstring
protocol variable enables this
support in the server. Form descriptors are best used with the
tag
protocol variable, which causes the form
data to appear using
ClientUser::OutputStat()
rather than
OutputInfo()
.
Select the protocol with
ClientApi::SetProtocol()
as follows:
client.SetProtocol( "specstring", "" ); client.SetProtocol( "tag", "" );
To obtain the descriptor containing the results of the method call,
your application must pass a StrDict
object to
ClientUser::OutputStat()
. Your application can override the
OutputStat()
method in a class derived from ClientUser
. The
Perforce C/C++ API calls this derived method, passing it the output
from the command.
Sending commands
The following example illustrates how you set up arguments and execute the p4 fstat command on a file named Jam.html.
char file[] = "Jam.html"; char *filep = &file[0]; client.SetArgv( 1, &filep ); client.Run( "fstat", &ui );
For commands with more arguments, use an approach like the following:
char *argv[] = { "-C", "-l", 0, 0 }; int argc = 2; char *file = "Jam.html"; argv[ argc++ ] = file; client.SetArgv( argc, argv ); client.Run( "fstat", &ui );
Processing data from the server
The Perforce server (release 99.2 and higher) can return tagged data (name-value pairs) for some commands. The following sections tell you how to handle tagged and untagged data.
Tagged data
The following example shows data returned in tagged format by
p4 -Ztag clients command. (The
-Z
flag specifies that tagged data is to
be returned; this flag is unsupported and intended for debugging
use.)
...client xyzzy ...Update 972354556 ...Access 970066832 ...Owner gerry ...Host xyzzy ...Description Created by gerry
To enable the Perforce server to return tagged data, your
application must call
SetProtocol("tag", "")
before connecting to the server. To extract values from tagged
data, use the GetVars
method.
The following Perforce commands can return tagged output. A release number, when present, indicates the first Perforce server release that supports tagged output for the command.
p4 add (2005.2) |
p4 fixes (2000.1) |
p4 protect -o |
p4 branch -o |
p4 group -o |
p4 reviews (2005.2) |
p4 branches |
p4 groups (2004.2) |
p4 reopen (2005.2) |
p4 change -o (2005.2) |
p4 have (2005.2) |
p4 resolve (2005.2) |
p4 changes |
p4 info (2003.2) |
p4 revert (2005.2) |
p4 client -o |
p4 integrate (2005.2) |
p4 review (2005.2) |
p4 clients |
p4 job -o |
p4 submit (2005.2) |
p4 counter (2005.2) |
p4 jobs |
p4 sync (2005.2) |
p4 counters (2000.2) |
p4 jobspec -o |
p4 trigger -o |
p4 delete (2005.2) |
p4 label -o |
p4 typemap -o (2000.1) |
p4 describe |
p4 labels |
p4 unlock (2005.2) |
p4 depots (2005.2) |
p4 labelsync (2005.2) |
p4 user -o |
p4 diff (2005.2) |
p4 lock (2005.2) |
p4 users |
p4 diff2 (2004.2) |
p4 logger (2000.2) |
p4 verify (2005.2) |
p4 edit (2005.2) |
p4 monitor (2005.2) |
p4 where (2004.2) |
p4 filelog |
p4 obliterate (2005.2) |
|
p4 fix (2005.2) |
p4 opened |
The tagged output of some commands may have changed since the command's first appearance in this table. The output of p4 resolve and p4 diff are not fully tagged. For complete details, see the release notes:
http://www.perforce.com/perforce/r15.1/user/p4apinotes.txt
To obtain output in the form used by earlier revisions of
Perforce, set the api
variable according to
the notes for
SetProtocol()
.
Untagged Data
To handle untagged data, create a subclass of
ClientUser
for every type of data required and
provide alternate implementations of
ClientUser::OutputInfo()
,
OutputBinary()
,
OutputText()
,
and
OutputStat()
.
Disconnecting from the server
After your application has finished interacting with the Perforce server, it must disconnect as illustrated below:
client.Final( &e ); e.Abort();
To ensure the application can exit successfully, make sure to call
ClientApi::Final()
before calling the destructor.
Performing file I/O
The default client file I/O implementation returns a
FileSys
object, which is described in
filesys.h
. To intercept client workspace file
I/O, replace the FileSys
*ClientUser::File()
method by subclassing ClientUser
.
The following example illustrates how you can override
FileSys
.
#include "p4/clientapi.h" class MyFileSys : public FileSys { public: MyFileSys(); ~MyFileSys(); virtual void Open( FileOpenMode mode, Error *e ); virtual void Write( const char *buf, int len, Error *e ); virtual int Read( char *buf, int len, Error *e ); virtual int ReadLine( StrBuf *buf, Error *e ); virtual void Close( Error *e ); virtual int Stat(); virtual int StatModTime(); virtual void Truncate( Error *e ); virtual void Unlink( Error *e = 0 ); virtual void Rename( FileSys *target, Error *e ); virtual void Chmod( FilePerm perms, Error *e ); protected: int nchars; } ; MyFileSys::MyFileSys() { nchars = 0; } MyFileSys::~MyFileSys() { printf( "Number of characters transferred = %d\n", nchars ); } void MyFileSys::Open( FileOpenMode mode, Error *e ) { printf( "In MyFileSys::Open()\n" ); } void MyFileSys::Write( const char *buf, int len, Error *e ) { printf( "In MyFileSys::Write()\n" ); printf( "%s", buf ); nchars = nchars + len; } int MyFileSys::Read( char *buf, int len, Error *e ) { printf( "In MyFileSys::Read()\n" ); return 0; } int MyFileSys::ReadLine( StrBuf *buf, Error *e ) { printf( "In MyFileSys::ReadLine()\n" ); return 0; } void MyFileSys::Close( Error *e ) { printf( "In MyFileSys::Close()\n" ); } int MyFileSys::Stat() { printf( "In MyFileSys::Stat()\n" ); return 0; } int MyFileSys::StatModTime() { printf( "In MyFileSys::StatModTime()\n" ); return 0; } void MyFileSys::Truncate( Error *e ) { printf( "In MyFileSys::Truncate()\n" ); } void MyFileSys::Unlink( Error *e = 0 ) { printf( "In MyFileSys::Unlink()\n" ); } void MyFileSys::Rename( FileSys *target, Error *e ) { printf( "In MyFileSys::Rename()\n" ); } void MyFileSys::Chmod( FilePerm perms, Error *e ) { printf( "In MyFileSys::Chmod()\n" ); } class ClientUserSubclass : public ClientUser { public: virtual FileSys *File( FileSysType type ); }; FileSys *ClientUserSubclass::File( FileSysType type ) { return new MyFileSys; } int main( int argc, char **argv ) { ClientUserSubclass ui; ClientApi client; Error e; char force[] = "-f"; char file[] = "hello.c"; char *args[2] = { &force[0], &file[0] }; // Connect to server client.Init( &e ); e.Abort(); // Run the command "sync -f hello.c" client.SetArgv( 2, &args[0] ); client.Run( "sync", &ui ); // Close connection client.Final( &e ); e.Abort(); return 0; }
The preceding program produces the following output when you run it.
% ls -l hello.c -r--r--r-- 1 member team 41 Jul 30 16:57 hello.c % cat hello.c main() { printf( "Hello World!\n" ); } % samplefilesys //depot/main/hello.c#1 - refreshing /work/main/hello.c In MyFileSys::Stat() In MyFileSys::Open() In MyFileSys::Write() main() { printf( "Hello World!\n" ); } In MyFileSys::Close() Number of characters transferred = 41
Handling errors
To encapsulate error handling in a maintainable way, subclass
ClientUser
at least once for every command you
want to run and handle errors in the
HandleError()
method of the derived class.
To best handle the formatting of error text, parse the error text, looking for substrings of anticipated errors, and display the rest. For example:
void P4CmdFstat::HandleError(Error *e) { StrBuf m; e->Fmt( &m ); if ( strstr( m.Text(), "file(s) not in client view." ) ) e->Clear(); else if ( strstr( m.Text(), "no such file(s)" ) ) e->Clear(); else if ( strstr( m.Text(), "access denied" ) ) e->Clear(); else this->e = *e; }
Connection errors
If any error occurs when attempting to connect with the Perforce
server, the
ClientApi::Init()
method returns an error code in its Error
parameter.
Server errors
The
ClientApi::Final()
method returns any I/O errors that occurred during
ClientApi::Run()
in its Error
parameter.
ClientApi::Final()
returns a non-zero value if any I/O errors occurred or if
ClientUser::OutputError()
was called (reporting server errors) during the command run.
To report errors generated by the server during an operation, your
application can call the
ClientUser::HandleError()
method. The default implementation of
HandleError()
is to format the error message and call
ClientUser::OutputError()
,
which, by default, writes the message to standard output.
HandleError()
has access to the raw Error
object, which can be
examined with the methods defined in error.h
.
Prior to release 99.1, Perforce servers invoked
OutputError()
directly with formatted error text.
Class overviews
The following classes comprise the Perforce API. Public methods for these classes are documented in “Public Methods Reference”.
ClientApi - Perforce server connections and commands
The ClientApi
class represents a connection with
the Perforce server.
Member functions in this class are used to establish and terminate the connection with the server, establish the settings and protocols to use while running commands, and run Perforce commands over the connection.
I/O is handled by a ClientUser
object, and
errors are captured in an Error
object. A
ClientApi
object maintains information about
client-side settings (P4PORT
, etc.) and protocol
information, such as the server version, and whether "tagged"
output is enabled.
ClientApi
does not include any virtual
functions, and typically does not need to be subclassed.
Any Perforce command that is executed must be invoked through
ClientApi::Run()
after first opening a connection using
ClientApi::Init()
.
A single connection can be used to invoke multiple commands by
calling
Run()
multiple times after a single
Init()
;
this approach provides faster performance than using multiple
connections.
ClientProgress - progress indicators for Perforce commands
The ClientProgress
class introduced in 2012.2
provides a means to report on the progress of running commands; you
can customize this behavior by subclassing
ClientUser
and
ClientProgress
.
In ClientUser
, implement
ClientUser::CreateProgress()
and
ClientUser::ProgressIndicator()
.
In ClientProgress
, implement
ClientProgress::Description()
,
ClientProgress::Total()
,
ClientProgress::Update()
,
and
ClientProgress::Done()
The methods of your ClientProgress
object will
be called during the life of a server command. Usually,
Description()
is called first with a description
and a
units
from the server; the units of measure
apply to the
Total()
and
Update()
methods.
Total()
is called if a there is a known upper bound to the number of units,
while
Update()
is called from time to time as progress is made. If your
Update()
implementation returns non-zero, the API assumes the user has also
attempted to cancel the operation.
Done()
is called last, with the fail
argument being
non-zero in case of failure. When the command is complete, the API
destroys the object by calling the destructor.
Default implementations are used in the p4 command-line client, and report on the progress of p4 -I submit and p4 -I sync -q.
ClientUser - I/O for Perforce commands
The ClientUser
class is used for all client-side
input and output. This class implements methods that return output
from the server to the user after a command is invoked, and gather
input from the user when needed.
Member functions in this class are used to format and display server output, invoke external programs (such as text editors, diff tools, and merge tools), gather input for processing by the server, and to handle errors.
Customized functionality in a Perforce application is most
typically implemented by subclassing ClientUser
.
In order to enable such customization, nearly all of
ClientUser
's methods are virtual. The default
implementations are used in the p4 command-line
client.
Error - collect and report layered errors
Member functions in this class are used to store error messages, along with information about generic type and severity, format error messages into a form suitable for display to an end user, or marshal them into a form suitable for transferring over a network.
Error
objects are used to collect information
about errors that occur while running a Perforce command.
When a connection is opened with
ClientApi::Init()
,
a reference to an Error
object is passed as an
argument to
Init()
.
This Error
object then accumulates any errors
that occur; a single Error
object can hold
information about multiple errors. The Error
can
then be checked, and its contents reported if necessary.
Although Error
itself does not provide any
virtual methods that can be re-implemented, the manner in which
errors are handled can be changed by re-implementing
ClientUser::HandleError()
.
The default behavior for handling errors typically consists of
simply formatting and displaying the messages, but
Error
objects maintain additional information,
such as severity levels, which can be used to handle errors more
intelligently.
ErrorLog - output error messages
The ErrorLog
class is used to report layered
errors, either by displaying error messages to
stderr
, or by redirecting them to logfiles. On
UNIX systems, error messages can also be directed to the
syslog
daemon.
FileSys - Perforce file I/O
The FileSys
class provides a
platform-independent set of methods used to create, read and write
files to disk.
You can intercept the file I/O and implement your own client
workspace file access routines by replacing
FileSys
*ClientUser::File()
in a ClientUser
subclass.
Note
Replacing the existing I/O routines is non-trivial. Your replacement routines must handle all special cases, including cross-platform file issues.
Unless your application has highly specialized requirements, (for instance, performing all file I/O in memory rather than on disk), this approach is not recommended.
If you intend to replace
File()
,
all of the virtual methods documented are required. The non virtual
methods are not required and not documented.
Ignore - support for rejecting files
The Ignore
class has two methods,
Ignore::Reject()
and
Ignore::RejectCheck()
.
Both methods are used by applications to determine whether files
destined to be opened for add will be rejected due to matching an
entry in an ignore files.
KeepAlive - support for client-side disconnection
The KeepAlive
class has only one method,
KeepAlive::IsAlive()
.
The method is used by applications to support client-side command
termination.
MapApi - logic for view mappings
The MapApi
class allows a client application to
duplicate the logic used by the server when interpreting and
combining view mappings such as branch views, client views, and
protections.
Each MapApi
object represents a single mapping
that is built by calling
MapApi::Insert()
to add new lines. A file can be translated through the mapping or
tested for inclusion by calling
MapApi::Translate()
.
Two MapApi
objects may be combined into a single
new MapApi
object (for example, a client view
and a protection table may be joined into a single mapping that
represents all files in the client view that are included in the
protection table) by calling
MapApi::Join()
.
Options - parse and store command line options
The Options
class encapsulates functions useful
for parsing command line flags, and also provides a means of
storing flag values.
Sample code is provided to illustrate how
Options::GetValue()
and
Options::Parse()
work together to parse command line options.
Signaler - interrupt handling
The Signaler
class enables the API programmer to
register functions that are to be called when the client
application receives an interrupt signal. The
Signaler
class maintains a list of registered
functions and calls each one in turn.
By default, after all of the registered functions have been executed, the process exits, returning -1 to the operating system.
StrBuf - string manipulation
The StrBuf
class is the preferred general string
manipulation class. This class manages the memory associated with a
string, including allocating new memory or freeing old memory as
required.
The StrBuf
class is derived from the
StrPtr
class, and makes heavy use of the
buffer
and length
members
inherited from the StrPtr
class. The
buffer
member of a StrBuf
instance is a pointer to the first byte in the string. The
length
member of a StrBuf
instance is the length of the string.
Most member functions maintain the string pointed to by the
buffer
member of a StrBuf
as
a null-terminated string. However, the Clear
member function does not set the first byte of the string to a null
byte, nor does the Extend
member function append
a null byte to an extended string. If you need to maintain a string
as null-terminated when using the
Clear()
and
Extend()
member functions, follow the calls to
Clear()
and
Extend()
with calls to
Terminate()
.
A number of member functions move the string pointed to by a
StrBuf
's buffer
, and change
the buffer
member to point to the new location.
For this reason, do not cache the pointer. Use
StrPtr::Text()
whenever the pointer a StrBuf
's
buffer
is required.
StrDict - field/value manipulation
The StrDict
class provides a dictionary object
of StrPtr
s with a simple Get/Put interface.
This class contains abstract methods and therefore cannot be
instantiated, but its subclasses adhere to the basic interface
documented here.
ClientApi
is a descendant of
StrDict
; most notably, the
StrDict::SetArgv()
method is used to set the arguments to a Perforce command before
executing it with
ClientApi::Run()
.
The
ClientUser::OutputStat()
method takes a StrDict
as an argument; the
StrDict
methods are therefore necessary to
process data with
OutputStat()
.
Note that pulling information from a StrDict
is
typically easier than trying to parse the text given to
OutputInfo()
.
StrNum - small numeric strings
The StrNum
class, derived from
StrPtr
, is designed to hold a small string
representing a number. Like a StrBuf
, it handles
its own memory. Unlike a StrBuf
, it does not
dynamically resize itself, and is limited to 24 characters, meaning
that the largest number that can be represented by a
StrNum
is 999999999999999999999999.
StrOps - string operations
StrOps
is a memberless class containing static
methods for performing operations on strings.
StrPtr - text operations
The StrPtr
class is a very basic pointer/length
pair used to represent text.
This class provides a number of methods for comparison and
reporting, but it is not in itself very useful for storing data;
the StrBuf
child class is a more practical means
of storing data, as it manages its own memory.
StrRef - refer to existing strings
The StrRef
class is a simple pointer/length pair
representing a string. The StrRef
class is is
derived from StrPtr
and does not add a great
deal of new functionality to that class, with the exception of
methods that make the pointer mutable (and therefore usable),
whereas a base StrPtr
is read-only.
As its name suggests, a StrRef
serves as a
reference to existing data, as the class does not perform its own
memory allocation. The StrBuf
class is most
useful when storing and manipulating existing strings.