Ingres CL ER
From Ingres Community Wiki
|
Ingres Compatability Library |
Compatibility Library Specification - ER
Abstract
This is the specification of the ER facility provided by the compatibility library.
Revision: 1.3, 26-Feb-1997
Document History
- Revision: 1.3, 26-Feb-1997
- Converted to HTML format.
- Revision 1.2, 23-Oct-1995
- ERinit() can now be passed routines to initialize and name the ER semaphore. (26-jun-1995)
- Revision 1.1, 29-Jul-94
- ERsend was transmogrified to an ERsend with different arguments, and returned as ERlog with the same arguments as the 6.5 ERsend (18-sep-92).
- Current ercompile programs truncate message number defines at 30 characters. This is wrong and should be fixed to at least 32. (25-sep-92).
- Revision 1.0, last modified 29-Aug-91.
- Removed references to ERreceive, which should not be documented at the CL interface. (Some systems don't have ERreceive).
- Corrected typos.
- Documented interaction with new NMsetpart function for unbundling.
Specification
Introduction
The ER routines perform all the processing for error message lookup, formatting and logging.
Library
CL and GL
Intended Uses
The ER routines are intended to be used by all CA-OpenIngres code, both frontends and backends. To convert any error code to text (including substitution of parameters) these routines must be called.
Definitions
| Message | Any string of text that is to be extracted from the code for possible translation. |
| Fast String | A message that needs very fast access (less than 100 msec) for repeated use. These include menu items, prompt responses, and common information messages. These messages will be cached in memory. |
| Slow String | A message that can afford 100 msec access time. These include errors, prompts, messages. |
| Class | The facility or subsystem identifier within which a given message belongs. |
| Class Code | The two letter identifier for a class. |
| Message Identifier | A unique number which identifies a particular message. |
| Message Source File | A commented text file containing the message identifiers and their associated text. This is created by the programming staff at Ingres Corporation, and can be translated by others. By coding standard, the extension for message source files is ".msg". The format of this file is described below. |
| Message Compiler | A program is called ercompile, taking as input a message source file, and creating a message header file and set of binary message files. See Chapter 3 for details. |
| Message Header File | A C header file, which contains #define statements for all message identifiers within a class. This file is automatically generated by the message compiler, and should not be hand edited. |
| Binary Message Files | The files (one for fast strings and one for slow strings) which are used by CA-OpenIngres at runtime to convert a message identifier into a piece of text. These need to be highly optimized for good message access performance. |
Coding Conventions for Messages and Strings
Message Policy
To ensure inter-version compatibility, it is critical that the following practice be observed.
Within the message files, no messages may ever be deleted. For existing messages, only the text associated with the message may be changed. If parameters are to be changed in any way, a new message id is to be assigned, and the old one left as is.
This policy applies to major releases as well as maintenance releases.
Fast and Slow Strings
All strings in the code must either be referenced through the ERget or ERlookup routines, or placed within the ERx macro. A special pass will be made over the code, which checks all strings to see if they are either dereferenced, or in the ERx macro. Any strings outside of it will be flagged as errors. The ercheck program (Chapter 3) can be used for these purposes. It is a coding standard that ercheck can be run on all of the code without producing errors.
Whenever the code is integrated into the CM system, the developer must take all translatable strings out of the code. Translatable strings are those that an end user would see, such as menu items and error messages. Non-translatable strings include things like form names and field names, and language keywords (since we are not translating the programming languages at this point).
Strings fall into two types: fast and slow. Fast strings are those that need frequent and fast access during the running of a program (less than 100 msec access time). These include menu items, prompt responses, and commonly used strings, such as "out of data". Slow strings are those that do not need such rapid access, and can afford a 100 msec real time hit before being used. These include messages, prompts, and error messages. Also, remember that only one slow string can be used via ERget at a time (since a static buffer is used) so you cannot use two references to ERget in the same call, for example. You can use ERlookup, however. It is the programmer's responsibility to assign fast and slow messages appropriately.
All translatable messages are referenced by ER_MSGID. An ER_MSGID is at least a 32 bit quantity which contains a message number, a class number, and an indicator as to whether the string is fast or slow. ER_MSGIDs are constructed in the following fashion:
- T_XXNNNN_CCC...
where XX is the two letter class code (normally corresponding to the directory for the frontends, and major component for the backends). A database of the class codes is maintained by RPM. All new classes must be registered in that database before being used. The T (for type) is one of the following:
| F | this is a fast message |
| S | this is a general slow message |
| E | this is an error message and status return and is always a slow message |
The NNNN is a four digit hexadecimal value, with leading zeros included. The CCC is any set of comments that you want to include in order to make the code more readable, separating words with underscores. Examples are 'E_DM0001_BAD_CONTROL_BLOCK' or 'F_QF0023_NextRow'. Only letters, digits or underscore are allowed in the comment section.
The ER_MSGIDs are also placed in the associated message source file for the class. This file is edited to include a line defining the text associated with an ER_MSGID, as in:
- F_QF0023_NextRow "NextRow"
- /* Get next row in query */
Any comments can be included, and the messages need not be in numerical order. However, you should be aware that the message compiler runs MUCH faster if the messages are in order. This file will be used by the translator to assign native language strings to your constants, so please make appropriate comments.
You should choose the number carefully, especially for fast messages. You should keep the numbers as low as possible, and as dense as possible, as the numbers become indexes in an in-memory array, so a sparse distribution will be memory inefficient. For slow messages, this caveat does not apply. To find out the 'next' available message number in a message source file, you can use the ernext command (Chapter 3), which will print out the next fast and slow message number, and any 'missing' numbers within the fast messages.
The erconvert program helps with the translation of strings to calls on ERget.
For internal system errors, please add a comment to the message file immediately following the message text which says "/* DIAG */" so that the translators do not bother translating unnecessarily.
Message Source Files
The naming convention for message source files is:
- erxx.msg
where xx is the two letter class code. The standard file header should be put at the top of the message file.
Messages in Static Structures and Shared Messages
To embed messages is static structures, you must switch from using character pointers to using ER_MSGIDs. When referenced, you can then use ERget with a variable name. If you need to use global variables with initialized messages, use the ER_MSGID for these variables. In that way, the string is defined in only one place, and other code can refer to those messages through the proper indirection.
Maximum Size of Message Strings
The maximum length for any string (fast or slow) is ER_MAX_LEN characters. ER_MAX_LEN is defined in <er.h>, and is currently 1000. It must not be made any less than that on any particular system. At some future date, the ER interface may be enhanced to remove the fixed length restriction, but at present there is a fixed upper limit.
You should note that English is a compact language, and English language messages are generally shorter than their translation in other languages. You should in general leave room for 50-75% expansion on messages in English. This is particularly important for IIUGmsg calls and IIUFask calls.
Strings with Embedded Special Characters
For strings that need embedded newlines in them (such as multi-line error messages), you can embed '\n' in the message (also, '\t' is NOT allowed--use spaces instead). In the message source file, strings which take up more than one line may be continued on the next line. This break is not considered significant, and will be treated the same as a space. For example:
- S_MN0232_Bad_Command_Line "Bad command line flag.
- Correct syntax is:\n\n
- PROGRAM dbname [-ijklmno]."
Message Classes
Each of the major components of the backend, and each directory of the frontends, is composed of a message class. You may also construct new classes as well, if needed for large tables of fast messages (such as large keyword lists). The primary benefit of this is twofold. It allows the translator to see all messages within a given class as a single group, and translate them together. Also, it allows you to use the ERrelease call when you are done with a static table to release all fast strings in large tables. Note that you need to define any new message classes as a two letter code, beginning with Z (reserved for classes which are not automatically defined for the directories or components). It is up to you to make sure that you do not conflict with any other such classes. A full list of existing classes is maintained in a database on the RPM development machine. Please use the user defined classes somewhat sparingly, as every program will start up with a dynamic array equal to the total number of classes in the system, so we should not go overboard on them.
Error Messages
All error messages in the system will be automatically extracted from the message files for the production of an Error Message Manual. As such, a set of conventions have been set up in order to make this process completely automatic. Also, conventions exist for the formatting of error messages for attractive and convenient display. Since users will see these messages, care should be taken in spelling, style and grammar.
Error Message Format
As mentioned before, an error message is indicated by the "E_" prefix. The message text for the error message should be placed in the following line(s), within quotes. This is the text that will seen by the user when the error occurs.
The display method used for error messages in forms-oriented front ends should be considered in designing messages. The first part of the error message is displayed on a single line with a continuation indicator at a word or newline break, allowing the user to press "return" to continue, or to press a function key to see the complete text, with the error number. For this reason, the first sentence of the message should be a brief summary intended to fit on one line, allowing an experienced user to distinguish the error and move on without asking for the expanded text. 40 or 50 characters is a reasonable guideline for the initial summary line, which should be ended with a hard newline, '\n'.
After this line, a more detailed explanation of the error should be put within the error message. This should be used to describe more fully the conditions and perhaps suggest some action to be taken. This information will typically be seen by less experienced users of the system who read the expanded text.
We have also devised a commenting convention to allow us to enter explanations and other information about the error message for placement in the manual (but which will not be seen interactively by users).
Immediately FOLLOWING the text of the message, a comment block should be given, starting with a single line containing /*%. This block should have each line beginning with a double asterisk, and contain four subsections, labelled as "Parameters", "Description", "System Status" and "User Action". These keywords should be placed on a line of their own, following a double asterisk and a single space, should be spelled exactly as shown, and should be followed by a colon. The text of each subsection should be single spaced, with each line beginning with a double asterisk and a single tab (or 8 spaces).
The Parameters section defines what the parameters in the message are. The Description section gives further information about what caused the error. The System Status section tells the user what the system will do (such as ignore the command, abort...), and the User Action section should tell what action the user should take next.
If you have messages identified with an E_ prefix which you do NOT want extracted to the Error Manual, such as status codes, you should begin the line containing the E_ identifier with a comment. For status codes, use /* STATUS */.
An example error message file might contain:
/* STATUS */ E_UG0000_OK "UG returns ok" E_UG0001_Bad_Language "A bad value of II_LANGUAGE was given.\n Incorrect value of '%0c' was specified for the name II_LANGUAGE. English will be used instead. Set the INGRES name of II_LANGUAGE to a valid supported language name." /*% ** Parameters: ** %0 Value specified by user for II_LANGUAGE. ** ** Explanation: ** This error occurs if a bad II_LANGUAGE is given. The message ** system uses a directory with the name of the II_LANGUAGE, ** and if that directory is not found, this error will occur. ** Since english is always available, it will be used. ** ** System Status: ** English will be used as the language for the messages. ** ** User Action: ** Set a valid value for the II_LANGUAGE name. */ E_UG0002_Bad_Msgid "A bad message id was found.\n An incorrect message identifier of '%0x' was sent to the error processing routine. This is an internal coding error, and should be reported to your technical support representative for INGRES." /*% ** Parameters: ** %0 Incorrect message identifier. ** ** Explanation: ** This error represents a missing error number which was ** found in an internal call. This should never occur, ** so it should be reported as a problem to your INGRES ** representative. ** ** System Status: ** Program continues. ** ** User Action: ** Report to INGRES technical support. */
Translation Comments
The developer is providing english versions of all message strings. A professional translator will be hired at some point to translate these messages into other languages, together with the forms and help file text.
It is the responsibility of the developer to put additional comments in the message text files to help translators understand the context and meaning of messages. Use them in particular where parameters are in the string in order to explain what the parameters are to be. If the parameter is drawn from of another group message strings, be sure to point this out.
Some guidelines are:
- For short messages, give a bit of context in a comment.
- Put comments in that indicate what product the message is used in, and where in the product. Then the translator can go try it out and see the context.
- If a string corresponds to a value in a field in a form, point it out, because this could be ripe for errors if the translator translates differently in the code and in the validation or trim in the form.
- If a string is to be placed onto a form, it is also important that the translator realize this so that they can adjust the form appropriately if they make the string a different length.
- Follow messages which need no translation (such as for diagnostic information) with a comment that says "/* DIAG */".
- Follow all error message with a comment block (see comments above).
- Keep menu items together whenever possible, and say that they are menu items.
- Say that prompts are prompts, and status messages are status messages. This lets the translator know how it will be displayed.
- Refrain from substituting whole phrases or nouns with modifying adjectives as parameters. It may not be possible to translate such substitutions in a grammatically correct fashion in other languages. *Ideally, all substituted string parameters should be single words, or entities such as validation strings or user programming language constructs which are not english to begin with, and will probably appear quoted in the error message, eg:
- "%0c '%1c' would be off the screen."
- where %0c is "Field", "Tablefield", etc. NOT:
- "%0c would be off the screen."
with the %0c argument having both words constructed into it. (In the above example, it would also be important to point out what message strings were used to draw "Field" and "Tablefield" from, so that the translator may lower case them if they no longer appear at the start of the sentence, or sentences aren't capitalized.)
- Documentation for strings which are used as parameters in other messages should include which message they are used in.
Conventions for Menu
Some special conventions are used for menus in order to help the translators in keeping menus together etc. Since a list of fast strings is not really adequate to show the structure of menus, and menus are a large part of what the translator needs to do, you are greatly encouraged to precede the entries for a menu in the message file with comments containing a description of where the menu is found so that the translator can quickly go to the product to understand the context. Feel free to use indenting structures to show the submenu structure of the product.
The special class, FE, is defined which contains some of the most common menu items (such as Help and End). Use these where appropriate. This is contained in the common frontend header directory, in erfe.msg (included in code by "# include <erfe.h>").
Header File <er.h>.
The header file <er.h> must be included before using any of the functions provided. It defines the following.
ERx - note non-extracted string
All literal strings within a program must be either referenced through calls to ERget or ERlookup in order to place them in message files. If any literal strings must be left in the source code, then they must be placed within the ERx macro, which simply returns the string which was sent. The reason for the macro is that we run a stript over the code to see if any literal strings are left in the code, and flag them as errors. Strings within the ERx macros will not cause this error, as the programmer obviously meant to include the literal in the source.
Inputs:
| str | pointer a literal, quoted string |
Outputs:
| None |
Returns:
| str | same as input |
Definition:
# define ERx(a) a
ER_ARGUMENT - format argument to ERlookup
This structure defines the type of parameter passed to ERlookup for value substitution.
typedef struct _ER_ARGUMENT
{
i4 er_size; /* Size of value in bytes. */
# define ER_PTR_ARGUMENT -1
/*
** Used by the frontend code to pass variable argument lists
** instead of control blocks (see ERlookup). If er_size
** is ER_PTR_ARGUMENT, the corresponding value is a pointer.
** This applies to all of the formats. By definition, if
** the format is 'd' the pointer is to a longnat, if it
** is 'f' it is a pointer to a double, if it is a 'c' it is
** a pointer to a NULL terminated string. if it is an 'x'
** it is a pointer to an u_longnat.
*/
PTR er_value; /* Pointer to value. */
} ER_ARGUMENT;
Executable Interface
The following functions are provided.
ERclose - Close message files (fast and slow)
Close fast and slow message files and release all memory for fast message and return status.
Inputs:
| None |
Outputs:
| None |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_NOFREE | |
| ER_BADCLASS |
Definition:
STATUS ERclose()
ERget - Return string pointer corresponding to ER_MSGID
This procedure searches the binary message files (either fast or slow) for the message corresponding to the ER_MSGID id and returns a pointer to a string which represents that id. The language is determined by the setting of II_LANGUAGE for this process.
If the id represents a slow message (high bit off), the return string points to a static buffer containing the message, after reading the message from the slow message file. Unlike ERlookup, the message name is not included in the returned string.
If the id represents a fast message (high bit on), the return string points to an in-memory version of the string, which will stay in memory until the class of the id is released either through a call to ERrelease or a call to ERclose.
If the id message cannot be found, a string is returned which indicates an error condition. If the message is longer than ER_MAX_LEN bytes, it is silently truncated.
This call must not be used in server. Use ERlookup instead.
Inputs:
| id | ER_MSGID key of message. |
Outputs:
| None |
Returns:
| A message string pointer (never NULL). It must return an internal message and return from all error conditions: |
| ER_DIRERR | if something cannot do LO call. |
| ER_NO_FILE | if something cannot do open on file |
| ER_BADREAD | if something cannot do read on file |
| ER_NOALLOC | if something cannot do allocate |
| ER_MSGOVER | if message table is over flow |
Side Effects:
| If slow message, this routine will overwrite the static buffer for slow messages, so only one slow message can be used at a time. |
Definition:
char * ERget(id) ER_MSGID id;
ERinit - Initialize the message system
This is used in order to explicitly initialize the message system. In non-servers, this is done implicitly upon first reference to a message routine. In a server, a more explicit call can be used in order to set some server-wide information, upon server startup. Since non-servers can set this information differently for each process, it is easy to use internal symbols for setting various global states, but the server cannot use this technique.
Three pieces of information are set by this call.
First, the ER_ASYNC flag records the fact that asynchronous IO is needed can be set by one argument. This allows the server to avoid blocking on error message reads.
The second flag, ER_MSGTEST, is used to direct the message system to use individual message files for each class, rather than the default use of one large message file for all messages. In production mode, for best performance, one large message file is used for all slow messages, and one large message file is used for all fast messages. While developing message files, and while translating message files, however, this is not very convenient, as the compilation of all message files at once can take a significant amount of time. Instead, by setting this flag, each message class is considered to be in a different set of two files (one fast and one slow), and each time a message is referenced, the correct file is opened and the correct message read. This, of course, is much slower than the other method, but quite good for developing new message files. In this mode, the class message files are identified by the leading s for slow or f for fast, followed by the decimal digits representing the class number. For example, the test message files for class 123 would be in files s123.mnx and f123.mnx. If this file is not found, control reverts to fastXXX.mnx and slowXXX.mnx in the same directory, where XXX is the first three chacters of the partname given to NMsetpart. (If NMsetpart wasn't called or if the file was missing, the filenames fast_v4.mnx and slow_v4.mnx are used as defaults.)
The third flag, ER_SEMAPHORE, is used to supply the ER system with p and v semaphoring routines (plus i and n semaphoring routines, if they are available) to be called before and after IO to the message file. In a multi-threaded server process (such as the DBMS) this is important. On some architectures (VMS, for one) a single process cannot have more than one outstanding 'read' posted to a given file. When this flag is set, ERinit() will assume that pointers to the p and v routines are being supplied, and will set up a static structure to hold them. At read time, these will be used to prevent one thread from posting an IO when another thread's IO is still in progress. If i and n routines are supplied, they will be used to initialize and name the sempahores.
For non-servers, which do not explicitly call the ERinit routine, the ER_ASYNC and ER_SEMAPHORE flags are always false. The test development system can be set by setting the variable/symbol II_MSG_TEST to any value.
Inputs:
| flags | Bit string representing the flags to set, which can be ORed together. The current valid masks are: | |
| ER_ASYNC | if async IO is to be used | |
| ER_MSGTEST | if individual class message files are to be used. | |
| ER_SEMAPHORE | If IO calls to the message file are to be semaphore protected. Setting this flag will tell ERinit() that the following four arguments are to be pointers to
| |
| p_sem_func | Only used if the ER_SEMAPHORE flag is set. Pointer to a CSp_semaphore() look alike routine, that will be used to request a semaphore before doing an IO to the message file. | |
| v_sem_func | Only used if the ER_SEMAPHORE flag is set. Pointer to a CSv_semaphore() look alike routine, that will be used to release a semaphore after doing an IO to the message file. | |
| i_sem_func | Only used if the ER_SEMAPHORE flag is set. Pointer to a CSi_semaphore() look alike routine, that will be used to initialize a semaphore before its first use. If NULL, this parameter is ignored. | |
| n_sem_func | Only used if the ER_SEMAPHORE flag is set. Pointer to a CSn_semaphore() look alike routine, that will be used to name a semaphore. If NULL, this parameter is ignored. |
Outputs:
| None |
Return:
| None |
Side effects:
| Sets the values of some static variables which are used in the internal routines. |
Definition:
VOID ERinit(flags, p_sem_func, v_sem_func, i_sem_func, n_sem_func) i4 flags; STATUS (*p_sem_func)(); STATUS (*v_sem_func)(); STATUS (*i_sem_func)(); STATUS (*n_sem_func)();
ERlangcode - Return internal code for language
This procedure returns internal code of language in parameter code, when passed a string representing the language. This internal code is used to discriminate internally language in program. If parameter language is NULL pointer, return default language code (code of ER_DEFAULTLANGUAGE or II_LANGUAGE).
Inputs:
| language | string pointer to language name |
Outputs:
| code | internal code for input language |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_BADLANGUAGE | cannot find language. |
Definition:
STATUS ERlangcode(language,code) char *language; i4 *code;
ERlangstr - get language string for internal language code
This procedure sets language string corresponding to internal language code. This function can make directory path for each language. Basically, this function has the opposite function to ERlangcode.
Inputs:
| i4 code | internal language code |
| char *str | buffer to set language string (It must be shorter than ER_MAX_LANGSTR). |
Outputs:
| None |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_BADLANGUAGE | missing language code number |
Side Effects:
| This function sets the language string (eg, "english") to pointed buffer. |
Definition:
STATUS ERlangstr(code,str) i4 code; char *str;
ERlookup - Lookup a message in the error file
Look up the text of the message associated with msg_number, substituting values passed in param for placeholders in the message text. If clerror is non-null, param is ignored. If, in addition, msg_number is 0, a system-dependent message about the CL error described by clerror is retrieved instead of a message. It is an error for both msg_number and clerror to be null. The resulting message is returned in msg_buf, which should point to a buffer whose size is msg_buf_size. The actual message size is placed in msg_length. Language specifies the desired message language. num_params is the number of ER_ARGUMENT members passed in param; this value must match the number of parameters specified in the error message format string found through msg_number. ERlookup will not attempt to substitute more than this number of parameters. ERlookup will count the format instructions in the unformatted message and return ER_BADPARAM if there are fewer (or more) than are specified in num_params.
If the generic_error pointer was non-null, the generic error code is filled in here.
ERlookup uses the following rules for handling msg_number, clerror and param:
- When clerror is not NULL and msg_number is zero, ERlookup will format the error message using the information in clerror.
- When clerror is not NULL and msg_number is not zero, the error number in msg_number is assumed to be a CL error number and the message is formatted using msg_number and information in clerror.
- When clerror is NULL, the error message is formatted using msg_number and the parameters pointed to by param.
- When clerror is NULL and msg_number is zero, it is an error.
- When calling ERlookup the following rules apply:
- When a CL_ERR_DESC is available, call ERlookup twice. The first call should set msg_number to the error number. For this call clerror should be set to the CL_ERR_DESC when the error number is a CL error and otherwise it should be set to NULL. The second call should set msg_number to zero and clerror to the CL_ERR_DESC. The second call should append data to the message returned by the first call.
- When a CL_ERR_DESC is not available, call ERlookup once with msg_number set to the error number and clerror set to NULL.
Errors returned by ERlookup should be handled by using a literal to format a message indicating the original error number and the return status. Then ERlookup should be called with the returned status and clerror set to the err_code from the first call. If ERlookup fails a second time, more text should be added to the message indicating a total failure.
Inputs:
| msg_number | The number of the message to look up. | |
| clerror | (Poss. null) ptr to CL error descriptor. | |
| flags | Formatting options. | |
| ER_TIMESTAMP | Affix a time stamp to the message. | |
| ER_TEXTONLY | Omit the message name/number from messages. | |
| msg_buf | Pointer to message buffer. | |
| msg_buf_size | Size of the message buffer. | |
| language | Language code for this session (as found by ERlangcode). | |
| num_params | Number of members of param array. | |
| param | ER_ARGUMENT array. |
Outputs:
| generic_error | The generic error code for this error. (if generic_error is NULL, no generic error code will be returned). |
| err_code | CL error descriptor. |
| msg_length | Resulting message text length. |
| err_code | OS system error, if status != OK. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_NOT_FOUND | |
| ER_NO_FILE | |
| ER_BADOPEN | |
| ER_BADPARAM | |
| ER_BADLANGUAGE | |
| ER_TRUNCATED | |
| ER_TOOSMALL | |
| ER_BADREAD | |
| ER_DIRERR | |
| ER_NOALLOC |
Definition:
STATUS
ERlookup(msg_number, clerror, flags, generic_error, msg_buf, msg_buf_size,
language, msg_length, err_code, num_params, param)
i4 msg_number;
CL_ERR_DESC *clerror;
i4 flags;
i4 *generic_error;
char *msg_buf;
i4 msg_buf_size;
i4 language;
i4 *msg_length;
CL_ERR_DESC *err_code;
i4 num_params;
ER_ARGUMENT *param;
Examples:
The following example shows a call to ERlookup with a CL_ERR_DESC:
status = ERlookup(error_code,
CLERROR(error_code)? clerror : (CL_ERR_DESC*) NULL,
ER_TIMESTAMP,
(i4 *)NULL,
buffer,
sizeof(message),
language,
&text_length,
&sys_err,
num_parms,
er_args );
if (status == OK)
{
length = text_length;
buffer[length++] = '\n';
status = ERlookup((i4) 0,
clerror,
(i4) 0,
(i4 *)NULL,
&buffer[length],
(i4) (sizeof(buffer) - length),
(i4) language,
&text_length,
&sys_err,
0,
(ER_ARGUMENT *) NULL );
}
The following example shows a call to ERlookup without a CL_ERR_DESC. It also shows error handling:
status = ERlookup(error_code,
(CL_ERR_DESC*) NULL,
ER_TIMESTAMP,
(i4 *)NULL,
buffer,
sizeof(message),
language,
&text_length,
&sys_err,
num_parms,
er_args );
if (status != OK)
{
STprintf(buffer,
"Couldn't look up message %lx ",
error_code);
length = STlength(buffer);
STprintf(&buffer[length], "(reason: error %lx)\n",status);
length = STlength(buffer.message);
status = ERlookup(status,
&sys_err,
(i4) 0,
(i4 *)NULL,
&buffer[length],
(i4) (sizeof(buffer) - length),
(i4) language,
&text_length,
&junk,
0,
(ER_ARGUMENT *) NULL );
if (status != OK)
{
STprintf(&buffer[length], "ERlookup failed twice");
}
}
ERrelease - release fast messages for class from memory
This procedure frees area of number table and message data for class class_no. It returns all memory associated with that class. Subsequent calls to ERget may reinitialize the class files.
It must not be used in server.
Inputs:
| class_no | ER_CLASS class number to free area. |
Outputs:
| None |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_NOFREE | if something cannot do MEfree |
| ER_BADCLASS | if class_no is incorrect |
Side Effects:
| Nulls out any pointers to fast class messages that may be in use. |
Definition:
STATUS ERrelease(class_no) ER_CLASS class_no;
ERreport - Lookup text for CL error message
Read the error message file looking for the matching error message test.
NOTE: This routine is obsolete. You should use ERget or ERlookup instead.
Inputs:
| err_num | The error number to lookup. |
Outputs:
| err_buf | The location to store error text. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_BADREAD | |
| ER_NOTFOUND |
Definition:
STATUS ERreport(err_num, err_buf) STATUS err_num; char *err_buf;
ERsend - route a message to the right place
This routine allows sending messages both to the log file and to a system-specific system log. With just the ER_ERROR_MSG flag, it is identical to ERlog() with no flag. In those cases, ERlog() is preferable to use.
With the ER_OPER_MSG flag, the message is logged to the error log file and also delivered to the system log. On Unix, this uses "syslog()". On NT, it uses "ReportEvent()". The message is given a severity of at least "error" when delivered to the system logger.
Inputs:
| flag | Indicate destination for the message, one of ER_ERROR_MSG or ER_OPER_MSG. (The ER_AUDIT_MSG flag is obsolete and should not be used.) |
| message | Address of buffer containing the message. |
| msg_length | Length of the message. |
Outputs:
| err_code | System specific error code. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_BADOPEN | |
| ER_BADSEND | |
| ER_BADPARAM |
Definition:
STATUS ERsend(flag, message, msg_length, err_code) i4 flag; char *message; i4 msg_length; CL_ERR_DESC *err_code;
ERlog - send a message to the error logger
This procedure sends a message to the system specific error logger. Normally there are multiple sender processes and a single logger.
If there is a receiving process, it may also send messages.
Inputs:
| message | Address of buffer containing the message. |
| msg_length | Length of the message. |
Outputs:
| err_code | System specific error code. |
Returns:
| OK | if operation succeeded, otherwise system specific error status. |
| ER_BADOPEN | |
| ER_BADSEND | |
| ER_BADPARAM |
Definition:
STATUS ERlog( message, msg_length, err_code) char *message; i4 msg_length; CL_ERR_DESC *err_code;
ERoptlog - echo an option into the errlog.log
This is a GL function added to support the removal of command line options to server processes.
ERoptlog() echoes a startup option and value into the errlog.log, trying to mimic the format produced by ule_format() (and others). ERoptlog() does minimal error checking: if ERsend() fails, the messages are simply not logged.
The option name may be in the format expected by PMget(), with exclamation points (!) and periods (.). ERoptlog() echoes only the component after the last ..
[NB: This should call ERlog instead.]
Inputs:
| option | The name of the option; it will be truncated in the log if longer than 32 characters. |
| value | The value of the option; it will be truncated in the log if longer than 64 characters. |
Outputs:
| None |
Returns:
| VOID |
Side Effects:
| Calls ERsend() to write to the errlog.log file. |
Definition:
VOID ERoptlog( char *option, char *value )
Support Programs
Note: On 25-sep-92, it was noted that current ercompile programs truncate message number defines at 30 characters. This is wrong and should be fixed to at least 32.
The following programs are presumed to exist to support the ER system.
ERcompile - message file compiler
The message compiler creates fast and slow binary message files and message header files. This program reads a set of class .msg files that describe the messages to be compiled, and outputs a fast binary message file, a slow binary message file, and and a set of header files that are placed in the location specified.
The fast and slow message files are accessed via the ERget and ERlookup calls in the code. Their location and naming convention is up to the implementor of the CL.
The command line syntax is:
ercompile [-a] [-l] [-o] [-h] [-s[file]] [-f[file]] classfiles
-a - Append the message into TMPFAST and TMPSLOW
-l - Save the temporary files.
-o - Sort the temporary files.
-h - Create the header files.
-t - Create the fast and slow files named with
the class name, so that the II_MSG_TEST
can be used. If this is used, it overrides
the -f and -s flags.
-sfile - Create the named slow message file.
-ffile - Create the named fast message file.
header file name - "<class name>.h"
default fast file name - "fast.mnx"
default slow file name - "slow.mnx"
Inputs:
| argc | Number of command line arguments. |
| argv | Array of pointers to the arguments. |
Outputs:
| None |
Returns:
| Error status if input files do not exist. |
Side Effects:
| Fast and slow message file and header files created in the current directory. |
Input file Format
Character Set
The ER compiler character set consists of uppercase letters, lowercase let- ters, digits, and special characters.
A letter is one of the following characters:
- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
- a b c d e f g h i j k l m n o p q r s t u v w x y z
ER compiler recognizes both uppercase and lowercase characters as distinct characters. Therefor, ER compiler is case-sensitive.
A digit is one of the following characters:
- 0 1 2 3 4 5 6 7 8 9
A special character is one of the following characters:
- = > < + - * % / \\ ( ) { } [ ] , . # ' " : ; & | ! ^ ? ~
Comments
A comments is explanatory text inserted within your program. Comments are ignored by compiler.
The slash character followed by an asterisk characrer introduces a comment. The compiler ignores all characters following the slash / asterisk combination until it encounters an asterisk / slash conbination. Comments do not nest.
The following is a comment:
- /* This is a comment */
Identifiers
An identifier is a sequence of letters, underscores (_), and digits. The compiler is case-sensitive.
The following are examples of identifiers:
- FCMN0001_Help
- SMNU0010_Out_of_range
- EQBF0100_DOES_NOT_EXIST_TABLE
Class Declaration
A class declaration has the following form:
- #define <class id>_class <class number>
- #define <class id>_CLASS <class number>
The Class id must be three characters; the Class number must be digits.
The following are examples of class declarations:
- #define CMN_class 1
- #define MNU_CLASS 10
- #define QBF_class 15
Message Declaration
A message declaration has a following form:
- F<class id><message number>_<strings> <string constants>
- S<class id><message number>_<strings> <string constants>
- E<class id><message number>_<strings> <string constants>
F is fast message id.
S or E is slow message id.
Class id must be the same as class name defined at class declaration.
Message number must be four digits.
Strings is a sequence of lettters, underscores and digits.
String constants is a sequence of zero or more characters enclosed in double quotes. This is the same as C string constants.
The following are examples of message declaration:
- FCMN0001_Help "Help"
- FMNU0001_Go "Go(Enter)"
- SQBF0010_JoinDefs "QBF - JoinDefs Catalog"
- SQBF0100_Use "Use the appropriate menu item to perform
- the desired operation on that JoinDef"
- EQBF0500_Error_Mes "ERROR: Invalid JoinDef name specified.
- Please enter valid name."
C Preprocessor Commands
You can describe C preprocessor commands.
Forms of Command:
- #define identifier token-string
Note that C preprocessor commands must be describe after class def- inition.
The following are the examples of C preprocessor command:
- #define CMN_HELP FCMN0001_Help
- #define CMN_END FCMN0002_End
- #define CMN_GO FCMN0010_Go
Output file formats
Temporary file
There is a text file created by parser with the following format:
- Gid<tab>Name<tab>Message<newline>
Sorted temporary file
There is a temportary file created by sort routine. It is possible to edit by text editor. The sort routione uses the DBMS
The file has the format
$Gid<newline>Name<newline>-^-Message<newline>-+-| | | +------------------+
for each amessage.
Fast Message file
This file fall into two parts. That is, There are index part and text part.
The following is the format of fast message file:
i4 number_of_class; -Control part-
struct control_r ---+
{ |
i4 number_of_message_in_class; |--- up to 2040 bytes
i4 length_of_whole_text_in_class; |
i4 distance_from_beginning_of_file;|
} ERCONTROL; ---+
.
.
.
i4 filler; (null)
-Text part-
char text[2048]; --- 2048 * n bytes
.
.
.
Slow message file
This file also fall into two parts, index part and message entry.
The following is the format of slow message file:
-Index page-
struct _INDEX_PAGE --+
{ | up to
longnat number_of_index_entries; |- 2048 bytes
longnat highest_index_key_corresponding_bucket |
} INDEX_PAGE; --+
-Data page-
struct _MESSAGE_ENTRY --+
{ |
i2 length_of_the_message_entry; |
i2 length_of_the_text_portion; |- * n bytes
i4 the_message_number_for_this_message; |
i2 length_of_the_name; |
char message_name_and_text[1031]; |
} MESSAGE_ENTRY; --+
Note that a data page is 2048 bytes, Messages are always a multiple of 4 bytes long, and messages do not span across pages.
Header file
The header file is text file created by parser, in the following format:
- #define<tab>Name<tab>Gid<newline>
Process Flowchart
+-----------------+
| |
| Check arguments |
| |
+-----------------+
|
|
|
+----+ +-----------------+
header | | | |
file | .h |<-------------| Parser |
..... | | -| |
+----+ - +-----------------+
- |
- |
- |
+----+ +----+ |
| | | | - temporary *
|fast| |slow| file * error *------------------+
| | | | * |
+----+ +----+ | |
- | |
- | |
- | |
- +-----------------+ |
-| | |
| Sort | |
-| | |
- +-----------------+ |
- | |
- | |
- | |
+----+ +----+ | |
| | | | - Sorted | |
|fast| |slow| temporary file | |
| | | | | |
+----+ +----+ | |
- | |
- | |
- | |
- +-----------------+ |
-| | |
| Builder | |
-| | |
- +-----------------+ |
- | |
- | |
- | |
+----+ +----+ |<----------------------+
| | | | |
|fast| |slow| - Message file |
| | | | |
+----+ +----+ |
|
|
< Exit >
ercheck - check for embedded strings not in ERx macros
The syntax of ercheck is:
ercheck [-l] [-d] [-s] {filename}
where -l is used to list the file names containing
strings only (as is done by grep).
-d is used to print out the lines containing
strings.
-s is used to check for single, rather than double
quotes.
ernext - show available messages in a message file
Given a message file, prints the next available message slow and fast message number. Optionally shows holes in the message file numbers.
ernext [-m] message_file
where -m if specified, list the missing numbers up to the maximum.
erconvert - convert a source file to have extracted strings
This program takes an input source file and message file, allows you to quickly convert strings to calls on ERget, and writes a new version of the source and message files with extracted messages. To run it, use:
erconvert
Use the Help for instructions on its use (this is an interactive program).
|
Ingres Compatability Library |
