Chapter 3.1
Programming using X2c
Date Arithmetic
X2c has special requirements for handling Date math. This is to allow the X2c optimizer to create better numeric code. The effect is that use of numeric constants or functions in date expressions must be changed as noted below.
The problem only occurs where numeric constants or functions appear, because numeric variables are not explicitly numeric and therefore do not activate the numeric optimizer in the same way.
The change is to use the function DAYADJ() to perform the date adjustment.
dBASE: X2c
datevalue = datevalue+1 datavalue = dayadj(datevalue,1)
datevalue = datevalue-1 datavalue = dayadj(datevalue,-1)
The error that is caused by not using DAYADJ() will show up by a run-time error "Dynamic variable (NAME) type N expected, found D".
Language anomalies:
There are a number of cases of date math where X2c gives errors on statements that appear fine. This will occur with any function that returns a date type including:
DATE(), CTOD(), LUPDATE(), STOD()
This is for cases of date():
dBASE: X2c
xvar1 = date() - xvar2 xtmp = date()
xvar1 = xtmp - xvar2
xvar1 = date() + xvar2 xtmp = date()
xvar1 = xtmp + xvar2
This situation occurs with ANY expression using the forms listed, such as 'if date()-xvar2' and 'do while date()-xvar2>0'
Compatible Clipper coding:
To have the same coding in a program running with Clipper as X2c,
add the following function to your code in a module not processed by X2c.
function dayadj
param p1,p2
return p1+p2
Data and index file functions
The standard file manager supplied for X2c is DBFA which provides dBASE compatible data files and a unique index file format.
Data files are of type .DBF and index files are of type .DNX, replacing dBASE index files of type .NDX .
Multi-user File and Record Locking
X2c uses the multi-user file manager to provide dBASE compatible file support. This has multi-user functions: RLOCK, FLOCK, LOCK and UNLOCK.
Locking Protocols:
The locking protocol uses error handling via the Xbase statement ON ERROR, and returns codes as listed below when files or records are in use. The ON ERROR procedure must to RETRY on these cases, even if different records are being accessed. This because the system must lock files internally at times, even if no user locks are requested.
The default setting is EXCLUSIVE ON, which also has the advantage of using file caching, which can not be used in a shared file situation.
The Clipper form using NETERR() can be enabled as described under NETERR() in the X2c reference manual.
File Creation:
The system creates files with permissions of 0666, however if the UMASK is not changed (the default is 022), then only the owner will be able to change files.
Networks:
If you plan to use a network of UNIX systems, check with your UNIX vendor to see if the UNIX locking functions properly span the network system.
Locking error codes,
check with error():
3 - File is in use
108 - File is is use by another
109 - Record is in use by another
110 - Exclusive open if file is required
111 - Can not write to read-only file
130 - Record is not locked
Handling Undefined functions:
When initially running X2c on a Clipper application, it is not abnormal to find a number of undefined functions. This is the result of many factors, including Clipper UDF's written in C, third party libraries used, un-documented Clipper features used (or hidden features), and occasionally, unsupported X2c internal functions.
A set of UNIX scripts have been created to make a dummy source file 'undef.c' which will give an error message when one of these is executed. This allows the program to be fully linked and started testing without resolving all the questions of the undefined externals.
The scripts are used by running 'cre_undef' when an undef external is found in the final X2c report.
Setting up to use these scripts:
The script m_TOP must be edited to add undef in two places:
The first line that contains 'cktimes' has 'undef' added before the final back-quote. (At approximately line 5).
The second line that contains 'gcc' has 'undef.o' added after the t_TOP.o, before the final backslash. Note: a space must be left between 'undef.o' and the backslash. (At approximately line 54).
Using the scripts:
To create a undef.c:
Run the following script sequence:
mt_undef
x2c
cre_undef
x2c
This will first create a empty (MT) undef.c, then run a full link. The error listing (TOP.rptc) is processed by cre_undef to create undef.c will have all undefined externals resolved. If cre_undef is run without running mt_undef first, only new undefined externals will be placed in the undef.c
Scripts:
cre_undef: script to create undef.c from map file
mt_undef: script to create eMpTy undef.c files
pr_undef: script to print undef.c (sorted)
Chapter 3.2
Programming for Unix
Moving files between machines:
File Formats:
The files of an Xbase application are of a number of different types. These are enumerated below. Each type needs to be moved using the appropriate approach.
program - as text files
databases - use binary transfer, or DBXULOAD
Indexes - recreate on other end, using INDEX ON
Memory files - need to dump to a creation program, use DBX3MEM
Moving techniques
Some or all of the files created by programs running under Xbase on a PC can be directly moved to a UNIX computer. The means to move file and programs is beyond X2c itself, but is provided by various other utilities or products. The ideal is a direct connection where the UNIX system can read a PC disk or both machines share a network with binary file transfer functions. Second best is a full range file transfer program with a protocol with binary and text formats, such as kermit.
Moving program files (of type .PRG and .FMT) requires text format transfers. This mode of file transfer handles end of line differences between systems. Text files under MS-DOS have return- linefeed at the end of each line, while UNIX files end each line with linefeed, called newline in UNIX. MSDOS text file may also end with a control-Z. These differences are converted automatically by the transfer package.
Xbase data files can be moved using a binary mode transfer. While the majority of a Xbase file is ASCII text, the header is binary and must be transferred as such. The utility 'dbxuload' will create an ASCII dump of a Xbase dbf file, with a text header that can be used to recreate the databases.
Xbase index files are machine and Xbase system dependent and should be re-created, not moved. Index files are recreated using INDEX ON statements.
Xbase memory variable save files are machine dependent and should be created, not moved. Memory files can be compatible, if the internal variable format is the same as on a 8086 machine. XENIX/UNIX on a 386 have comparable memory files. Memory files can be dumped using the dbx3mem '-a' option to a PRG source file. Memory files can be recreated using a memory variable SAVE statement added at the end of the PRG created by dbx3mem.
Label files are not handled by dBx and must be replaced with inline code. X2c included the code to read LABEL files and output labels.
Report files are not handled by dBx and must be replaced with inline code. X2c included the code to read REPORT files and output reports.
If you have a lot of report files, check out the shareware program FRM2PRG, which will create an Xbase PRG from a report format file.
For systems where binary transfers are not available, or if the DBFA file manager is not to be used on the UNIX system, the files should be copied to delimited format by DBXULOAD.
If you are stuck, call Desktop Ai customer service for a utilities disk that includes programs to simplify the process. If no other versions are available, source to KERMIT for a UNIX system, can be obtained from Columbia University. Most good PC communications packages contain Kermit support.
SCO XENIX/ SCO UNIX scripts:
AT and 386 versions provide the doscp utility to move files from a MSDOS disk to a XENIX disk. Use the -r switch to move database (.DBF) files. Do not use the switch for text files.
The script get.from.dos handles wild card handling for doscp. It takes one parameter, which is the dos device (and directory) as doscp would use, ie. 'get.from.dos x:' would load all files from a 1.2 meg dos floppy.
Make sure you use lowercase names when transferring, as XENIX is case sensitive, unlike MSDOS, and, per XENIX naming conventions, all names are lower case. get.from.dos creates all files with lower case names.
Linux MSDOS File systems
The easiest way to move files for linux is just to mount the DOS directories as msdos file systems and copy the files. Then run 'rmcr' on the .prg's. Even this is not usually necessary since most UNIX editors show DOS files fine, just with extra '^M' characters for the carriage returns at the end of each line, and X2c does not care if they are there or not. Make sure to run 'addcr' when moving prg's back to DOS.
UNIX Screen/Terminal Handling
If you are moving a Xbase application from one type of machine to another, you may encounter hardware limitations because of equipment differences. Often, the screen display characters and color options differ from one screen to another. Many standard CRT terminals do not support color at all. Many Unix systems support most screen features, except color, but these are only effective with terminal speeds in excess of 4800 baud and small window areas.
The key areas that need handling are:
25 vs 24 line screens
Extended PC characters (those <32 or >127)
Function keys
Color
Screen refreshing
Screen Size and Character Set:
How serial terminals differ from a PC screen
No PC special characters on most terminals, and those that do may have different output codes.
When a PC is used as a intelligent terminal, most communications packages provide support for standard PC characters. Certain Wyse terminal have PC equivalent characters.
24 lines instead of 25
Screen re-painting:
UNIX terminals are usually connected to the computer system with serial links, slower than MSDOS computer consoles. To improve the console update time, the terminals are updated using a UNIX sub-system called curses.
Curses is designed to be able support the wide variety of terminals available. This system uses the TERMINFO or TERMCAP databases to define the terminal control sequences as described elsewhere.
Curses minimizes the output sent to a terminal to improve output performance. This requires the program to tell curses when to update the screen. X2c handles this automatically for normal screen situations.
Output from '?' operations are forced to the screen for each operation.
Output from '@' operations are output on a keyboard operation, such as READ or WAIT.
When status messages are output using '@'and no console wait occurs, then the message is never output to the screen - until the next console wait. This code can occur as a 'please wait' message in a large processing section of a program.
To force these messages to the screen, place a inkey() statement after the @/SAY used to output the message. No pause will occur and the message will be output. ESCAPE or other function key processing will occur.
The statement 'call SCpaint' can be used to just update the screen, but not scan for
To cause each '@' operation to be immediately output to the screen, the function HWsetref can be used:
call HWsetref with .T. && Force all output to be immediate
call HWsetref with .F. && Optimize output
RUN command programs:
The programs that a RUN command executes are local to the system on which the program is executing. This means:
"RUN DIR *.X >filename"
will not work under Unix, the proper statement is:
"RUN ls -l *.x >filename".
In addition, the Unix Shell (/bin/sh) has special characters that DOS Command.com does not have, such as '$'. This is used by Shell to create a temp name. This means:
"RUN ls -l *.x >temp.$ID"
will not produce the file temp.$$$ but temp.#####ID, where the ##### was an ID filled in by the shell.
To understand the difference, write test programs and study shell operations.
Be careful of '*' as a wildcard. DOS *, as in 'DEL *' removes only files with no 3 character extension. In unix, 'rm *' removes EVERYTHING !!, with no checking to see if you meant it.
Directory Path Names Differences:
UNIX filenames have a path using forward slash (/) instead of backslash (\) as in DOS. There is no disk specifier (A:) and file extensions (the dot part) are not fixed at three characters or one dot, in fact, a dot is just like any other character. Some Unix systems are limit filenames to 14 characters in the last path component, most allow the total path length at 64 or 128 characters. Some network file names start with a double slash and the remote machine name (//machinename/).
Full Unix filenames are case sensitive and can be any mix of upper and lower case, with NAME, Name and name all being different files. X2c forces all filenames to lower case so the PRG logic does not have to change.
X2c can automatically flip MSDOS slashes and can substitute a UNIX path for the x: disk specifier. See statement SET DRIVESPEC TO.
Printer control:
Unix provides a sophisticated spooling system for printing. X2c allows taking advantage of this by connecting the printer output to a unix pipe, rather than a physical file.
The only problem with Xbase programming is that there is no explicit action that says for the print spooler to take the file. X2c uses the standard Xbase language in a way to allow the programmer to start the printer when a report is done.
The following rules apply:
The default printer is a pipe to:
lp
Any SET PRINT ON/OFF just routes output to the printer pipe. It will be automatically opened if it was never opened or was closed previously.
SET PRINT TO
This will close any current printer output and start printing.
SET PRINT TO |command-string
This will open the printer pipe to the given command string and set the default printer to this new command.
For example, to set the pipe output to the file my_printer, then use the command:
SET PRINT TO |cat >my_printer
SET PRINT TO file-name
This will open the printer to the file-name.
For example, to set the output to the file my_file, then use the command:
SET PRINT TO my_file
SET PRINT TO empty-string
Reopens the pipe to the previously used command. This will cause any prior command to finish, hence starting the spooler and reconnecting the pipe.
On the other hand, this would overwrite the output file my_printer in the above example. To flush the output pipe and add to a prior file, the command above would be:
SET PRINT TO |cat >>my_printer
This command can be issued by either:
SET PRINT TO ("")
or
dummy = ""
SET PRINT TO &dummy
Chapter 3.3
Typical Problems
The Following is a list of and resolutions for many common user problems.
Xbase compile Errors
'Out of Dictionary Space':
Change the dictionary size. Use DBX3SU to set the dictionary size at greater than the default (about 850). Under the options menu is the choice 'Maximum number of variables' which allows you to set the maximum. 2500 is about the maximum that will fit in a 640k MSDOS system, UNIX systems allow 6000 or more fields. Picking a number too large will cause a smaller legal number to be chosen, but X2c may run out of memory on later operations.
After you run DBX3SU, make sure to re-PRG or x2c_scan your system or the new dictionary size will not be in the batch files.)
C Compiler errors and warnings:
"Unable to open ????????.H"
This indicates that no C compiler has been installed or there is a major configuration or installation problem as UNIX C compilers are in a fixed location. Use the x2c_tconfig script to test the x2c configuration.
"Invalid comment" or "warning invalid escape character"
This warning can be ignored. If it is an error, the literal needs to broken.
The SET COLOR TO [options] has the char '*' and '/' as valid input. The X2c compiler places extra backslash (\) escape code to break up '*/' or '/*' sequences.
"Warning: pointer assignment conflict"
DO NOT IGNORE THIS WARNING.
This warning can have many different phrasing. It indicates that a pointer expression does not match a function prototype. It applies to either a built-in X2c function or a UDF. In either case, it might indicate a error in the X2c generated C code and should not be ignored. If no obvious Xbase error is found, Email technical support a code sample.
Link Time errors
Unresolved externals:
First determine the source of the missing external, the error message will include the name of the missing external and usually, what module(s) are requesting the external.
If you recognize a procedure or function of your own, then make sure the X2c analyzer found all your modules. Add EXTERN and VAR FUNCTION statements as needed.
All X2c functions start with regular names codes:
DB - file operations
SC - screen operations
str - string operations and the like
VA
AY - ANY-type variable functions
HT - Memo functions
If these are missing, the corresponding X2c library can not be found.
If the missing names have peculiar letters, such as G12da, or you can find the function in your C manual. Then you are probably missing a standard C compiler library - make sure your C compiler is fully installed.
Unresolved external 'dbx_s?' or 'dbx_a'
This indicates a error in the generated Xbase code. It usually occurs because the C code produced with an Xbase error is compiled. Correct the Xbase error and re-run X2c.
Duplicate external definition:
There are no conflicts between X2c libraries and C libraries However different C environments have unique system functions. For example, if a user prg was called system(), this will conflict with the standard function in UNIX C to call the shell.
Then took for another user name 'system', such as a UDF. Check other sections for discussions of 'name scoping' in C.
Run Time Errors:
Screen Operations:
NUMERIC DISPLAY and ? output
Display looks different, as it usually will. Although we recommend using @/SAY/PICT or STR()/TRANSFORM() for pretty output, X2c will make DISPLAY and ? output for numeric variables closer to other Xbase dialects. The effect is for SET DECIMALS to be always in effect. The format will usually not be the same as other Xbase dialects.
Database:
The X2c file manager operates according to Xbase rules and read/write Xbase data and memo files (.DBF/ .DBT). X2c uses its own index file format. To create X2c indexes, have INDEX ON statements in your program or just write a short program doing USE and INDEX ON for each index you want to create.
Index file types (.DNX vs .NDX)
.DNX is the default type for X2c index files. If you specify another index type, it will over-ride the .DNX and be used as the name of the file. It will not effect the file internal format. You can not specify .NDX and expect to use dBASE indexes, or .NTX for clipper indexes - the format will still be X2c index format.
Numeric Indexes are not supported.: (dbx only)
Use STR(field) to create character strings in INDEX ON, SEEK and SET RELATION statements. Make sure to change all SEEK and SET RELATION statements to use the STR() function, these will not work.
FILTERs on related database fields
Not supported, nice item but it won't work. This is a non-documented feature of other dialects.
REPLACE on non-select areas
Where REPLACE specifies an ALIAS different than the current work area. This does work in X2c and other dialects, although it is specifically illegal in the dBASE documentation.
Directory control:
SET PATH and SET DEFAULT work. On SET PATH use standard DOS semi-colons between directories.
LIST lists only one or no records
You need to specify fields and ALL keyword in LIST command
Index not found or can not be opened:
X2c has its own index format, in a DNX file. You can not just rename another index file and have it work.
SEEK Failure
Seek seems to fail where the index key is a concatenation of two or more fields, then SET EXACT OFF statement must added if searching on only first part of key.
General Notes:
ALWAYS CHECK VERSION OF ALL SOFTWARE INVOLVED
Using incompatible versions can create subtle errors that can produce almost any result.
Please use the latest version of all software. It is not possible to upgrade software AND support all older versions - X2c is supported for the latest version of each related product. Where they exist, older versions may be provided as a courtesy only and are not supported.
Chapter 3.4
Hints and Tips For using X2c
Brief Users (and other smart editors):
The X2c system creates error files of type .err when compiling a .PRG into a .C and when compiling a .C to a .OBJ. These are of the correct format so you can use the control-P/ control-N macros for Find error and Next error.
These files follow the standard format used by various C compilers on MSDOS and UNIX. They are recognized by brief on DOS and emacs and jove on UNIX.
Debugging Aids in executable X2c programs:
These may be activated by placing the switch on the command line, in upper case.
Trace: -T
By placing the -T in front of any command line parameters, you can enable a line trace in the lower right of your screen. You need to have done the X2c compile with the TRACE option on from the DBX3SU setup program for a whole system, or statement OPTION TRACE ON in a single module. Turning TRACE on for a whole system is very costly in memory, so use the OPTION statement during debugging to bracket the problem areas and remove the OPTION statements when done
Debug: -D
This is the debugging tool of last resort, as it turns on massive internal dumps from the database libraries. If you are absolutely stumped and technical support can't help with an easy answer - they will tell you how to use the results. The library source is mandatory to make sense out of the dumps.
How should you convert systems with multiple PRG files:
This is the norm for any significant system and X2c is designed to handle such systems. Regardless of the size of the system, there is only one TOP (top) PRG and one DBD file, which is named 'TOP.DBD'.
An application system in X2c is defined as all Xbase PRG sources that make up one .EXE running program. X2c always adds one source file called c_TOP.c and may add one source file called t_TOP.c, if the system uses databases and not only menus.
Each additional PRG is found when the TOP (top) PRG is scanned.
UDF's in different PRG's:
These are handled as part of each PRG. There are not different 'TOP.PRG's, only one system TOP (top). Once the PRG is recognized, it can contain straight line code, and PROCEDURE's and FUNCTION's.
How many C_TOP.C are required?
A C program must have only one 'main()' function. X2c creates this is the source file 'c_TOP.c'. There is only one per .exe in a system.
Big Xbase applications:
Some issues to be considered in converting a large application.
Dictionary size:
Make sure to set the X2c dictionary size to a large enough value. 3000 can be set on a PC, and is sufficient for most systems. Unix systems allow over 6000.
Process approach:
Start with sub-trees. Break the application into major sections. For example, a 25,000 line application can be divided into five 5,000 sub-systems.
Test all common sub-functions first. Create test jigs to test functions so they can be used reliability as the larger system is assembled.
Build up and stub sections. Assemble the system as if it were being done for the first time. Make sure to test each section as it is integrated.
Final integration:
When ready to create a final application, use the X2c analyzer from the TOP of the final application. Do not try to integrate the application by hand, let the X2c system do the work.
C Compiler limitations:
Maximum size of a single procedure.
Be aware that most C compilers are designed to process certain types of program structures. In particular, they expect a large number of small functions. In contrast, a compiled Xbase program produces one monolithic C function. This can overload the C compiler and, if so, will cause a fatal compiler error, often a STACK OVERFLOW or HEAP OVERFLOW. To avoid this, divide the Xbase program into a number of smaller procedures. In addition, this will result in an easier to maintain program.
BIG compiler versions
Some C compiler have two versions, for difference sized programs. When available, use the version designed for Big programs. It will be slightly slower, but less likely to overflow on big programs. Do not confuse the BIG program compiler with the Large memory model on PC compilers. You will always need to use the Large memory model, regardless of the size of a single program.
How to disable SYdeb() calls:
These calls are the result of having the TRACE option enabled. This option can be set globally via DBX3SU or the in-line OPTION TRACE statement.
Disable from DBX3SU menu options/trace and re-running PRG or x2c_scan step. Make sure no OPTION TRACE ON statements are in source code.
NOTE: The DBX3SU setting is reflected by the statement SRC_TRACE=1 in the environ.def control file.
X2c supports C defined variables NO_TRACE and NO_TRACE2 to defeat SYdeb() calls.
European Character set
To properly create X2c programs for European customers, the special characters must be taken into account. The standard X2c library does not do this and requires changes in a number of areas including:
Display and GET field
Sort, Index and Comparison order
Calling from a C program
When calling a X2c program from a C program, it is most important to study the main() function in c_top.c. Make sure to execute all the initializer functions only once before a X2c program is called, and the shut-down functions only once after all calls to the X2c program are done.
Overlays
UNIX applications do not needed to be overlaid because of the virtural memory capabilites builtin to UNIX.
UDF's in User functions:
The major interactive functions (MEMOEDIT(), DBEDIT(), ACHOICE()) have special support for user functions in expression arrays. This applies to any parameter where an expression is passed as a string. These are passed to the expression evaluator and must reference the UDF via the run-time table in the t_top.c file.
Make sure to define the user function in the DBD with a FUNCTION statement and place a "CONFIG MACRO PROC function-name" statement after the FUNCTION statement. This is to place the function in the macro function reference table. The form "CONFIG MACRO PROC ALL" at the end of the DBD will place all functions and procedures in the macro table. The normal X2c include file x2ctail.dbd has these statements.