This is a description of some of the main features of the Symbian software platform's implementation of the C Standard Library (normally referred to as STDLIB). It provides information on how it differs from other such libraries and descriptions of some of its main features. It does not attempt to document the library's entire API. For such documentation, see the following:
for documentation of the ANSI C and POSIX specifications, see the relevant organisations' web sites (http://www.ansi.org and http://standards.ieee.org/index.html).
For literature on ANSI and POSIX specifications, see POSIX Programmers Guide— Donald Lewine O'Reilly & Associates, Inc.— ISBN 0-937175-73-0
The following are some of the reasons behind the implementation of STDLIB:
to address the porting requirements of C software engines to the Symbian software platform.
to provide an ANSI C library with associated POSIX system calls.
to support both pure C programs and mixed C/C++ programs.
to provide the standard include file structure with the standard #defines
and function prototypes.
The following are not among STDLIB's design goals:
to support pre-ANSI C compilers.
to pass ANSI or POSIX conformance test suites.
to support POSIX-style tools executed from a shell. The Symbian software platform does not provide such a shell, nor does it provide a sophisticated text console.
to be the C API for the Symbian software platform. For example, STDLIB does not provide any new C functions for supporting threads or active schedulers.
to provide new C++ interfaces. The public API for STDLIB is the C functions themselves, and almost no aspects of the underlying C++ implementation are exposed, even to C++ programmers.
Many ANSI standard functions have been implemented, including all those in stdio.h
and math.h
. The functions which have been implemented are those in the STDLIB header files whose prototypes are preceded by the IMPORT_C
macro.
STDLIB's maths library, math.h
, provides the mandatory ANSI maths functions. Most of these use the underlying Symbian maths functions, encapsulated by the Math
class.
Many functions, including bsearch()
, qsort()
, memcpy()
, and tolower()
are little more than a call to a corresponding function provided by the Symbian software platform. In many cases, this function may be found in Symbian's User
class. For example, malloc()
and free()
simply call User::Alloc()
and User::Free()
respectively.
The STDLIB implementation of printf()
does not take into account the format specifier for floating point values. Instead, the implementation uses TDes8::Format()
with a Symbian software platform format specifier which is derived from the style, width and precision of the original printf()
specifier. The result does not obey the rules for ANSI printf()
for some combinations of number width and precision, and formats the numbers using the thousands separator taken from the Symbian software platform locale; see class TLocale
.
The Symbian software platform identifies some errors as being fundamental programming errors and will abruptly terminate the offending thread (referred to as a panic). POSIX never does this and will always return error conditions instead (though some errors will result in signals, e.g. segmentation faults).
POSIX processes exist in a hierarchy with children inheriting resources from their parents — the "fork and exec" model of process creation. In the Symbian software platform, processes have no association whatsoever with the thread which created them. They are created by constructing a fresh instance of an executable image.
The Symbian platform provides limited text console support, intended for debugging of low-level components.
An open file in the POSIX system is a process wide resource that can also be inherited by child processes. In the Symbian software platform each thread within a process has separate resources within the shared process address space and open files are private to a given thread.
Open POSIX files are inherently shareable, so multiple processes can write to the same file simultaneously. In the Symbian software platform open files are inherently non-shareable, and even the thread which has the file open is only allowed one outstanding write operation at a time. For more information on files, see the RFile
class.
The Symbian software platform does not support global data in DLLs. To overcome this, STDLIB uses a structure, _reent
(declared in reent.h
) an instance of which is allocated to each thread to hold the errno
value, some "static data areas" used by functions such as ctime()
, and the STDIO data structures.
The Symbian software platform has different client classes for each type of resource: files, sockets and the console are all different and have different APIs. POSIX file descriptors can refer to all of these different resources and have a common API (though many functions will actually only work on socket file descriptors).
The Symbian software platform processes do not have a notion of a current working directory. The closest notion is the session path, as set and retrieved by class RFs
.
The Symbian software platform does not have a way of pre-empting a thread and causing it to execute a different piece of code, so there is no true equivalent of a POSIX signal or signal handler.
Simple C programs may not need to support file descriptors shared between threads, or the execution of sub-processes. Such programs may use the default implementation of STDLIB, in which the library code opens files, sockets etc. in the context of the calling thread, and provides a per-thread table of open file descriptors.
Multiple threads may still be used, but each thread's resources are private and cannot be shared with other threads. For example, a setenv()
call in one thread will not be seen by a getenv()
call in another and each thread will have a separate console window (created on demand when the console is first read from or written to).
More complex programs may need to use process-wide resources. This is often true of programs which assume the existence of support for multiple threads within a POSIX process. To meet this requirement, STDLIB can operate in a mode in which all shareable resources are owned by a single CPosixServer
thread. In this mode, library routines such as open()
, read()
and write()
operate by passing an appropriate request to the CPosixServer
.
The program's mode of operation is determined when it first tries to use STDLIB's services. If a CPosixServer
is running for the Symbian software platform process, the thread will use it; otherwise the program will operate in the single-threaded mode.
The CPosixServer
is a Symbian software platform active object, and can be started either in the context of an existing active scheduler, or by spawning a separate thread to run an active scheduler. The functions for doing this have a C++ interface, defined in estlib.h
. For more information on active objects in the Symbian software platform, see active objects.
Communication between CPosixServer
s is used to establish the POSIX process hierarchy and to communicate resources from parent to child. Programs which require multiple processes must use the multi-threaded mode of operation.
Most error codes reported by STDLIB functions correspond to the standard C error code values. Some of these are identified within STDLIB, which produces the correct errno
value directly; most are reported by translating the Symbian software platform error codes into equivalent errno
values using a translation table. Occasionally, a Symbian software platform error code may be reported untranslated. In this case, it will have a negative value. For a list of the Symbian software platform's error codes, see System wide error codes. STDLIB does not usually attempt to detect inputs which will cause an EPOC panic, (for example attempting to accept()
on a stream socket which has not been bound). Such a panic will terminate the offending thread, which may in turn result in the termination of the whole process. For more information on panics in the Symbian Software platfrom, see Panics.
A normal Symbian executable provides an E32Main()
function which is called by the operating system to start the program. The file ecrt0.lib
provides an E32Main()
function for projects which use STDLIB. This function prepares the traditional argc
and argv
arguments and passes them to main()
.
For a simple example demonstrating how to link to ecrt0.lib
, see the description of the project specification for "Hello World" in Porting.
The user of STDLIB does not need to use ecrt0.lib
, and may provide their own E32Main()
. In this case, a CTrapCleanup
pointer should normally be provided. This pointer is required because although STDLIB does not call Symbian functions which can leave, it does use some functions which require a cleanup stack. Code in ecrt0.lib
provides such a cleanup stack ("TheTrapCleanup
"), but programs which do not link with ecrt0.lib
will need to supply one directly. For more details on the motivation behind Symbian's use of the cleanup stack, see Cleanup support.
STDLIB provides a POSIX-like abstraction of file descriptors which unifies the different types of resource and permits a single API to be used across all of them. This is a significantly different approach from Win32 and the Symbian software platform, both of which have separate APIs for each distinct type of resource.
STDLIB supports files stored in the file system, sockets, a console, and a /dev/null
device. The first time STDLIB initialises its internal file descriptor table it creates an emulated console device and attaches it to descriptors 0, 1 and 2. The emulated console device will appear as a window when it is first used (i.e. when the program writes to or reads from the console).
The open()
function recognises the following names:
CON:
is taken to mean a newly-created console. This will never be the same console as the one automatically associated with 0, 1 and 2.
NUL:
is taken to mean a /dev/null
device.
TMP:
is taken to mean a temporary file, which will use the underlying Symbian software platform file system facilities to create a uniquely-named temporary file, and will cause the file to be deleted after it has been closed cleanly.
COMx:
is the serial port where x is a number from 1 to 9. COM1:
corresponds to serial port zero and so on.
IRCOMx:
is the serial port where x is a number from 1 to 9.
The number of open files in the file has no explicit limit.
EPOC resources such as RFile
s and RSocket
s are derived from class RSubSessionBase
, so are thread specific. This means they cannot be used by any thread other than the one which opened them. In STDLIB however, the CPosixServer
, if running, controls the master file descriptor table. In this case, all STDLIB threads in a process may share their resources, because the STDLIB implementation forwards all i/o requests to the resources owned by that process's CPosixServer
thread. If no CPosixServer
is running, each thread has a separate file descriptor table and the resources are not shareable.
The STDLIB console (encapsulated by class CTtyDesc
, defined in fdesc.h
) is a client of the CConsoleBase
class implemented by econs.dll
. It provides very simple text input and output with no support for embedded control sequences. When STDLIB receives a character from the console it prints it out to the same console, providing a "local echo" facility to make simple command-line interfaces possible.
STDLIB does not provide any sort of terminal driver or line-discipline. In particular there is no support for local processing of backspace, nor any line buffering. Neither does it provide termio or termcap facilities. The Symbian software platform is a graphics-based system and it is recommended that C code be ported into a Symbian program which uses a graphical user interface.
All STDLIB i/o operations are blocking; that is they will suspend the calling thread indefinitely until the i/o completes. So in general, STDLIB i/o should not be used in an EPOC active object because it will cause the entire active scheduler to block. A possible way to avoid this problem might be to use fcntl()
for individual file descriptors, but STDLIB does not currently implement this function.
Asynchronous i/o may be achieved using a set of C++ functions provided by STDLIB which implement a per-file-descriptor equivalent of the POSIX select()
function. These functions provide a form of the ioctl()
function which takes a TRequestStatus&
as a parameter, together with functions for completing the ioctl()
operation once the status has been signaled or canceling the pending ioctl. This scheme can be used within an active object to wait for a socket to become ready for reading or writing, so that the subsequent i/o does not block the whole active scheduler. See estlib.h
for the interface to these functions. For more information on active objects and the active scheduler in EPOC, see active objects.
Note that there are no such blocking problems with i/o to local files, which is essentially a synchronous operation.
The POSIX interface is designed for a single thread of execution within a process. Many aspects of this interface do not apply to a typical Symbian program in which multiple threads of execution share the same address space. For information about threads and processes, see Threads and processes.
STDLIB allows for multiple threads, but each thread owns its own instance of the _reent
structure which contains private data such as the thread's errno
variable. Each thread's STDIO FILE
structures are completely separate from other threads', even if those structures eventually share the same underlying file descriptor. A consequence of this is that different threads will buffer their output to stdout
separately, even though the eventual output will be combined together when the STDIO layer flushes the buffers out to the corresponding file descriptor.
It is unclear how some POSIX functions should be used in a multiple thread environment. An example is the exit()
function. Although each thread should have separate atexit()
processing, which should include closing all open STDIO files, it is unclear whether closing the STDIO file should also close the underlying descriptor. STDLIB's current implementation is to close the files, as would be expected to happen in a normal POSIX process. However, this implementation may be changed. Note that exit()
does not attempt to free memory which was obtained by malloc()
.
The user of STDLIB can take control over thread termination by implementing exit()
, _exit()
, abort()
and _assert()
in their own program, so that all of the user's own code which calls these functions will invoke the user's routines instead of the STDLIB versions. A helper function, _atexit_processing_r()
, can be called from the user's version of exit()
to do the normal atexit
processing, if desired. See stdlib_r.h
for details.
The Symbian software platform file system APIs require all filenames to be fully specified, possibly by using default components in the session path. For more information, see the documentation on the file server (File server). In particular, the file system does not support the notion of a "relative path" which uses "." and ".." to navigate relative to a "current working directory". STDLIB does support this and does not require fully qualified paths, with the constraint that any pathname beginning with "<letter> :" will be treated as an absolute path from the root of the specified drive. STDLIB allows the drive letter '?' to mean "any drive". This can be useful when a file or directory is known to exist but it could be on any drive. STDLIB allows both "/" and "\" as directory separators, unlike the underlying Symbian file system which recognises only "\".
The current working directory is a process-wide resource (similar to the file descriptor table), so the CPosixServer
will provide a single process-wide current working directory. However, when using the "single-threaded" mode of operation, each thread will have a separate current working directory.
The following table gives some examples, all based on a working directory of c:\documents\stdlib
|
In summary, the POSIX and STDLIB handling of pathnames is DOS-like, with the exception that there is not a separate working directory per drive.
The Symbian file system supports DOS-like attributes, rather than POSIX-like permissions. STDLIB cannot therefore provide the full POSIX-like handling of file attributes and implements only "user read permission".
The Unicode changes for Standard Library come in two groups:
impact on the existing "char*" interfaces
addition of new "wchar_t*" functions which use Unicode directly
The Symbian platform is a Unicode-based operating system, so all operating system services which use text require that text to be presented in the 16-bit Unicode character encoding known as UCS-2. For the Standard Library on the Symbian platform, this is most significant in dealing with the names of files and directories, all of which are now Unicode sequences.
To minimise the impact of this change on existing narrow C code, the Standard Library has adopted the policy that all such names in char* interfaces will be interpreted using the UTF-8 standard for encoding Unicode strings as 8-byte sequences. UTF-8 is a no surprises encoding and matches the 7-bit ASCII encoding for character codes 0 to 127, so existing string handling code will work without modification.
The wchar_t
type is defined and ISO-C standard wide character constants are supported. The wchar_t
definition chosen is unsigned short to match the use of UCS-2, and a range of relevant functions now have wide character analogues which use wchar_t*
in place of char*
, for example:
FILE * fopen (const char *_name, const char *_type);
FILE * wfopen (const wchar_t *_name, const wchar_t *_type);
and
DIR * opendir (const char *);
WDIR * wopendir (const wchar_t *);
Where such a pair of functions exists, the char*
interface is implemented by converting the UTF-8 parameters to Unicode and calling the matching wchar_t*
interface.
The mbtowc
family of conversion functions is provided to convert between UTF8 and Unicode, but there is no additional support for locales or other forms of multibyte encoding; to convert from encodings such as Shift-JIS, programmers are recommended to use the CHARCONV conversion routines via C++ wrapper functions callable from C.
There are no implementations of wchar_t*
versions of STDIO functions such as fputc
.
Symbian has no plans to provide the following in the Symbian software platform C Standard Library:
float-sized maths operations. POSIX requires only double-sized operations. Primitive arithmetic operations on float values can be carried out, and all of the standard printf
format specifiers including %E
and %e
are supported. However, none of the floating point library functions declared to take float-sized arguments are supported. For example;
double sqrt (double d); // Supported by STDLIB
float sqrtf (float f); // Omission
mapping the ANSI locale functions onto the Symbian TLocale
functionality. Instead the locale is a fixed "C" locale. Therefore STDLIB engines may not be localised. It is recommended that localisation be implemented at the Symbian software platform application level.
select()
. The POSIX select()
function is not implemented in STDLIB because the Symbian software platform does not in general support asynchronous "ready to read" or "ready to write" notification.
signal()
. A Symbian thread cannot be made to spontaneously execute a "signal handler", so signals have not been implemented.
fork()
or exec()
functions