Overview

EditWriter

This help file was last updated: April 13, 2010

Overview to EditWriter

You are viewing the updated CDC EditWriter developed for the Windows environment. While the Edit Engine and any Metafiles created by EditWriter may be used with other platforms, the EditWriter is strictly a Windows program.

EditWriter starts up without opening a Metafile. Use the Open command from the File Menu (or the open button from the toolbar) to open an existing metafile. This version can open only a single Metafile at a time, but you may run multiple sessions of EditWriter if you wish to view more than one Metafile concurrently.

The program will prompt for agency and password before opening a Metafile. If the Metafile is opened without the proper agency password, all objects may be viewed, but only those objects without any agency association may be modified.

After selecting a Metafile to open, the program will create some working files. This process may take a few seconds. When EditWriter opens a Metafile created by an earlier version, it will convert the earlier Metafile into the format required for the current version. It is important to note that this format is NOT backward compatible, so be careful to work with a copy of your Metafile during testing or to save the converted Metafile under a new name until you no longer need the earlier version Metafile for production. As a Windows program, EditWriter will allow you to save the Metafile with a long name (i.e., longer than the DOS 8.3 format that was required under EditWriter version 2).

Once the Metafile has been opened, the metafile constituent objects are listed in the Navigational Panel on the left side of the workspace. All objects may be opened for viewing or editing from the Navigation Panel.

Navigation Panel

View Object


About EditWriter Help

This help file was produced for the National Program of Cancer Registries (NPCR) from a selected portion of the EditWriter v2.0 Manual to provide assistance with the EDITS Language to EditWriter users who are writing edits. It has been extensively expanded to cover the features introduced in EditWriter v3 and the EDITS Language additions introduced with EditWriter v4.

For more information, contact cancerinfo@cdc.gov.


Elements of an EDITS Metafile

A metafile is a container of objects (known as Metafile Constituent Objects, or MCOs) used to apply data quality business rules to data elements.

There are seven MCOs:

Agencies | Any entity that creates MCOs for a metafile. Usually, these are standard-setters or central tumor registries. However, they can be any person or organization.
Edits | Computer software algorithms that check the content of data fields against an encoded set of acceptable codes and subsequently provide feedback on the quality of the data. The algorithms are specified using the EDITS language, a simplified programming language designed to validate data.
Edit Sets | Collections of Edits.
Fields | Descriptors for data fields. Data type is a string, or a string representation of numeric, date or boolean values.
Record Layouts | Collections of Fields. Data is submitted to the EDITS Engine in fixed-position ASCII format. The Record Layout is the roadmap to the data file.
Messages | Re-usable error messages that are returned from the EDITS Engine when an Edit fails.
Tables | Look-up tables provide an internal reference library for EDITS processing.

MCO Interrelationships

The interrelationships among these objects looks like this:

Agencies are optionally associated with the other six MCOs. That is, an object may be "owned" by an Agency, but it does not have to be.

Layouts are containers of Field objects. Field objects may be associated with more than one Layout container.

Edit Sets are containers of Edit objects. Edit objects may be associated with more than one Edit Set, or no Edit Set. The EDITS Engine provides means for running Edits in batches (that is, run the Edits in a specific Edit Set), or individually.

Edits have optional associations with Fields, Tables, and Messages. It is technically feasible to write an Edit that does not reference any field, table or message objects, but it is rarely useful to do so.

Avoid Common Mistakes!

With the foregoing in mind, here are a few tips for creating an effective metafile:

  • Ensure the fields referenced in an edit exist in whatever Record Layout you plan to use. (When the Edit Workspace Form is open and has the focus, you can click on the [image] button on the toolbar to select a record layout. A message will tell you whether the fields in the edit exist in the layout. You can also perform this check for all Edits in an Edit Set; when the Edit Set form is open, choose menu option Edit Set | Check Against Layout. )

  • An Edit generally must be included in an Edit Set to be run by client software. (Most software vendors use EDITS API function EEx_RunBatch; however, it is possible to run an Edit that is not in an Edit Set if the software uses API function EEx_RunEditByName.)

  • An Edit Set that has no Edits will be excluded from the runtime metafile (*.RMF).

  • An Edit that contains syntax errors in its logic will not be included in an Edit Set when the runtime metafile is generated. (You will be warned about this when you generate the RMF.)


Quick Start

Quick Start for the New EDITS Author

This page is designed for the new author who will be creating or modifying Edits Metafiles. If you have experience with the CDC EditWriter 2.0 (the DOS version), you may find this page helpful, but you should also read Conversion from EditWriter 2 and Known Problems.

A Metafile is a type of database, made up of many component parts that, given a data stream, will look for inconsistencies within that data stream.

The key element of the Metafile is the Edit or Edit Object, which contains the program logic to look for data errors. The Edit Object also contains text fields that allow you to document the purpose of the edit and how an end user might resolve an edit error.

As the Metafile author, you will write or update the edit logic to look at and compare specific Data Fields or Field Objects. The Field Objects hold the data values in memory in the Metafile so that the Edit Object can apply its validation tests.

Sometimes these tests will check for specific data values within the edit logic. Other times, the Edit will use a User Table or Table Object to look up valid values or combinations of values. As of v4.0 of the EDITS tools, an Edit may make calls to external libraries (Dynamic Link Libraries for Windows, shared objects for Linux) to retrieve information.

When the Edit Object detects an error in the data being checked, it must report that error with an Error Message or Message Object so that the inconsistency can be resolved.

Edit Objects can be grouped into Edit Sets that will be applied together against the data stream. Each Edit Set can be custom designed for specific types of data streams. For example, a Metafile Edit Set that is used for a central registry database where data is consolidated may not be appropriate for a hospital registry that doesn't have access to some data elements (e.g., geocoding location), and an Edit Set that is used for a hospital registry may not be comprehensive enough for a central registry.

The data stream itself requires another object, the Record Layout, so that the data stream can be parsed into Data Fields for the Edit logic.

Finally, there is an Agency or Agency Object, that confers ownership on all of the other objects in the Metafile. This means that, for example, a state registry can create an Edits Metafile that can be distributed to hospital registries and software vendors and that cannot be modified because the state registry has protected its Edits and Edit Sets with a password.

If you are just beginning to work on Metafiles, you will probably find it easier to download the latest NAACCR Metafile and use the pre-defined Edit Objects to assemble a new Edit Set. Once you have more confidence, you can try your hand at writing your own Edit Objects (using existing edits as guides), and perhaps building some Table Objects to validate Data Field values.

Once you have your Metafile ready to distribute, you should compile it into a Runtime MetaFile (RMF). As with any software program, the computer can run the program code more efficiently in a compiled format. The Centers for Disease Control has also produced a set of additional programs, GenEDITS Plus and the Edit Engine, that read the data stream from a file, read the compiled Metafile and apply its tests to the data stream, retrieving the edit errors and formatting them into a report for the end user.


Conversion from EditWriter 2

Conversion from Earlier Versions of EditWriter

Conversion of a Metafile created in EditWriter 2 or 3 to the current version format occurs automatically when you open the Metafile in EditWriter. Once the Metafile is open, the program will suggest that you save it in the new format. The next time EditWriter opens it, it will recognize that it already has been converted and will not go through that step again, saving a little time and opening it up for you more quickly (it also makes the import process go more quickly). If you will still need to release updates to your Metafile in the prior version format, you should save the converted version under a different name.

There are some issues that you should be aware of before you open (or import) a version 2 Metafile in EditWriter:

  • EditWriter 2 does not "finish" a Metafile until it compiles it. Some links between objects (e.g., messages in an edit, edits in an edit set, etc.) do not get written until the Metafile is compiled into an RMF. Be sure to compile your version 2 Metafile before opening it in EditWriter.

  • The Windows version of EditWriter requires a password for each agency. If you created an agency entry in EditWriter 2 to "protect" your edits and tables, but did not associate a password with your agency, you should do that before converting your Metafile to the current version. If not, you will not have the access rights to update your edits, edit sets, messages, tables, and the like. It is possible to overcome this problem in EditWriter, but it's not pretty.

  • In EditWriter and by agreement of the Edits Work Group, the edit object attribute Error Correction Help has been renamed to Administrative Notes in the current version and should be used for logging the change history and information about how to select from related edits when building an edit set. The Edit Description attribute is now devoted to error correction help. Applications that are designed to extract edit help at runtime should use the EDITS API functions to extract the Description (EEx_GetEditDescript) instead of the one to extract from the old ERRCORRECT field (EEx_GetEditHelp). Refer to the Edit Engine API documentation for details. (Contact Technical Support at edits@askcnet.org for a copy of the API.)

  • If you are planning to import objects into a current version Metafile from a version 2 or 3 Metafile in stages, you should first open the prior version Metafile with EditWriter and save in the current version format. You will save time because EditWriter must convert an earlier version Metafile into the current version each time it opens it and before it can compare and import objects.


Opening a Metafile

The EditWriter program starts up without opening a Metafile. Use the "Open" command from the File Menu (or the Open button from the toolbar) to open an existing Metafile, or use the "New Metafile" command (or the New button) to create a new Metafile. The program can open only a single Metafile at a time, but you may run multiple sessions of EditWriter if you wish to view more than one Metafile concurrently.

If you create a new Metafile, the program will prompt for a name for the new Metafile.

The program will prompt for agency and password before opening a new or existing Metafile:

If an existing Metafile is opened without the proper agency password, all objects may be viewed, but only those objects without any agency association may be modified. Otherwise, the user may modify those objects for which agency permission has been granted.

If a Metafile has been opened without logging in, the password prompt can be displayed by clicking the Login button or selecting Login from the File menu or by pressing ALT+F+L.

After selecting a Metafile to open, the program will create working files. This may take a few seconds. When EditWriter opens a Metafile created by an earlier version, it will convert the earlier Metafile into the current version format. When it has finished the conversion, the program will display a reminder:

It is important to note that this format is NOT backward compatible with EditWriter 2 and therefore not compatible with the DOS GenEdits program, but those tools are many years out of date and you should not be working with them any longer. As a Windows program, EditWriter 3.0 will allow you to save the Metafile with a long name (i.e., longer than the 8.3 DOS format).

Once the Metafile has been opened, the metafile constituent objects are listed in the Navigational Panel on the left side of the workspace.

Navigation Panel


Navigation Panel

All of the constituent objects - Agencies, Edits, Edit Sets, Data Fields, Record Layouts, Edit Messages, Tables - of the open Metafile are listed in the Navigation Panel at the left of the workspace. This panel is always open while the Metafile is open; closing the Navigation Panel will close the Metafile.

To switch from one list to another,

  • click on the tab at the bottom of the panel, or

  • select "View" from the menu at the top of the window, then select the list you want to view, or

  • press CTRL+n, where n corresponds to the number on the tab at the bottom.

When there is more than one column displayed, clicking on the caption at the top of the column will sort the list by that column.

As each list is displayed, the menu at the top of the window will change to include a drop-down menu specific for that list.

You may search for an object in the list by typing in the name or number of the object, depending on which column is active. To search by Message number, for example, you must click on the top of the number column (Msg#) of the Message list. If you want to search for a Data Field by the local name, you must click on the Local Name column. As you enter text, your search string is displayed at the top of the list. Press [Escape] or click in the list to clear the search string.

To limit the number of objects in the list (e.g., only edits within one edit set), you may apply a filter. Filters for different objects may be applied to different attributes, depending on the object. See Filters for more information.

To open an object to view it or modify it, highlight the object's name and

  • double click on it, or

  • use the drop-down list menu and select "Launch," or

  • click on the Launch button [image], or

  • press CTRL+L, or

  • drag the object's name onto the workspace.

Objects may also be opened from within other object forms by all of the above means except double clicking.

Metafile Objects:

Agencies

Edits

Edit Sets

Data Fields

Record Layouts

Messages

User Tables

Filters

Toolbars and Buttons


View Object

Viewing Objects

Once you have opened a Metafile Constituent Object, you may view its attributes. Modification of the object may be restricted by password permissions.

To open an object to view or modify it, highlight the object's name and

  • double click on it, or

  • use the drop-down list menu and select "Launch," or

  • click on the Launch button [image], or

  • press CTRL+L, or

  • drag the object's name onto the workspace.

Objects may also be opened from within other object forms by all of the above means except double clicking.

See Toolbar and Buttons.

Agencies

Edits

Edit Sets

Data Fields

Record Layouts

Messages

User Tables


Filters

Filters in the Navigation Panel

You can limit the number of objects in a list on the Navigation Panel. At the minimum, you can filter on the date the object was last modified. For some objects you have more options than for others.

For Edit Sets and Record Layouts, the only option is to filter on date. For Agency objects, no filter options are available (there are usually only a few agencies anyway).

For Edit objects, you may filter on

  • a word or phrase in the Edit Name

  • a word or phrase in the Description, Administrative Notes, and/or Edit Logic (note: checking more than one attribute will show Edits with the word or phrase if it occurs in any checked attribute)

  • date last changed

  • whether the Edit is in a defined Edit Set or in no Edit Set at all (note: checking more than one Edit Set will show only those Edits in all checked Edit Sets)

  • the agency owning the Edit

  • whether an attribute is empty or not

  • single field Edits vs interfield Edits

A second page for the Edits filter allows you to include selection by Fields. You must move the selected fields into the right column by highlighting the field name in the left column and clicking on the right arrow for them to be applied in the filter. Remove fields by highlighting the name in the right column and clicking the left arrow.

For Edit Messages, you may filter on

  • a word or phrase in the Message text

  • date last changed

  • whether messages are used in any Edits or no Edits

For Data Fields, you may filter on

  • a word or phrase in the Standard Name

  • a word or phrase in the Description

  • date last changed

  • whether the Data Field is used in any Edits or Record Layouts or not used in either Edits or Record Layouts

For Tables, you may filter on

  • a word or phrase in the Table Name

  • a word or phrase in the Description

  • date last changed

  • whether the table is used in any Edits or in no Edits at all

For each filter, you can enter criteria, then click [Apply] to see the results. You can modify the criteria and click [Apply] again, or you can remove the filter by clicking [Clear].

When you have applied a filter to the list of objects on the Navigation Panel, the program marks the top of the list to remind you that you are not seeing all of the objects. You may keep the filter dialog box open or minimized on the workspace, or you may close it without changing the filtered display on the Navigation Panel. If you do close the filter dialog box, you must reopen it to clear the filter or change the filter characteristics.

To clear all filters and set new filters on a list, click on the [Clear] button.


Toolbar

Toolbars and Buttons

At the top of the workspace, EditWriter offers several sets of buttons on the toolbar. These buttons are dynamic, in that they may become inactive, or "grayed out," when the workspace where they are functional becomes inactive (e.g., closed or moved behind another window). Other buttons become functional only when appropriate, such the SAVE button which becomes active only when the object has been modified

To assist in learning these buttons, there is a RESIZE [image] button at the leftmost position. Clicking this button will toggle between the standard (icon only) buttons and a larger set of buttons that include captions. If you move the mouse over a button, the caption will be displayed as a tooltip.

The toolbar buttons are grouped by the program area where they work:

  • Metafile operations

Create New Metafile

Open Existing Metafile

Save Metafile

Copy Metafile

Generate RMF

Login

  • Navigation operations

Launch (Open) Object

Add New Object

Delete Object

Copy Object

Filter List

  • Object Form operations

Launch (Open) Object

Previous Object

Next Object

Save Object

Save Object As

Print Object

  • Logic Writer

Pick Function

Pick Language Construct

Pick Field

Pick Table

Pick Constant

Pick Message

Check Syntax

Check Edit against Record Layout

  • Test Bench

Test Edit

Clear Edit Results

Check Edit against Record Layout

For convenience, the workspace forms also contain the PREV [image], NEXT [image], SAVE [image], and CLOSE [image] buttons.

The Edit Workspace Form also displays a TILE [image] button on some tabs to allow you to view some attributes side-by-side.

The Test Edit page also displays a Debug [image] button which lets you see which lines of the logic executed, and the changing values of variables.

See Edit Workspace Form.

See also Reports


Agency Workspace Form

When you open an agency into a workspace form either by opening an existing agency object or by starting a new agency object, all of the properties of the agency are displayed, except for the password. You may enter or change any of the information on the form.

Agency ID is pre-assigned for state registries, standards organizations, and software vendors; choose the Agency ID from the drop-down list. If your organization is not listed in the drop-down list, contact Technical Support for assistance (edits@askcnet.org).

Assigning an agency to an object confers "protection" of that object from modification, unless you have entered the password for that agency during login. For example, if an Edit Set is created without an agency (i.e., the field on the Edit Set form is left blank), anyone may add or delete Edits from the Edit Set. Otherwise only someone who can enter the agency password can modify the Edit Set.

You may set or change the password for an agency by

  • selecting "Password" from the agency object menu at the top of the window, or

  • clicking the Password button on the form, or

  • pressing ALT+A+P

  • enter the new password twice (note: passwords are case-sensitive)

  • click [OK]

Changes to an agency object's attributes may be saved by

  • selecting "Save" from the agency object menu, or

  • clicking the [Save] button on the form, or

  • pressing CTRL+S.

Changes to an agency attribute cause the attribute to turn red. When you save these changes, the agency name in the Navigation Pane will be highlighted in red.

If you make changes to an agency object and attempt to close it without saving, the program will prompt you to save it or discard the changes.

Creating New Objects

Deleting Objects


Edit Workspace Form

The Edit Object is so complex that there are multiple tabs to this form. You may select the attributes to view by clicking on the tab at the bottom or by pressing CTRL+1 through CTRL+6.

The first tab, Overview [CTRL+1], displays some of the attributes of the edit and will allow you to modify the edit name and/or the agency code. At the bottom, it also lists the data fields and user tables used in the edit and the edit sets which contain this edit. You may open a data Field, a User Table, or an Edit Set with the "Launch" selection on the edit logic menu, or the [Launch] button [image], or CTRL+L.

The second tab, Description [CTRL+2], displays the descriptive text explaining the intent of the edit and how it works, including suggestions to an end user about how to clear an edit error. You may make changes to the description here.

The third tab, Logic [CTRL+3], displays the edit logic, as written in the Edits Language. The LogicWriter offers tools for pasting Fields, Functions, Tables, Messages, Constants, and Language constructs into the edit logic. When the active window shows the edit logic, the LogicWriter Toolbar is active, or you may pop up a tools menu by pressing F2. You may run the syntax checker by selecting the button from the tool bar. Syntax errors are displayed below the edit logic window. Double-clicking on an syntax error message will take you to the line where it was generated. The actual error may be earlier in the logic.

The fourth tab, Administrative Notes [CTRL+4], is for recording information about the edit that is unrelated to the edit logic itself but is useful to record about the edit. For example, a history of changes to the edit may be logged here. See Conversion from EditWriter 2 for redirecting edit help calls to the Edit Engine.

The fifth tab, Error Messages [CTRL+5], allows you to change the default error message by clicking on the messages button to display the list of available messages and to rearrange the data fields to display properly when the error message macros are expanded. In addition, the program will display any other error messages imbedded in the edit logic. You may open any message listed here by highlighting it, then selecting "Launch" from the edit logic menu or by clicking on the [Launch] button [image] or by pressing CTRL+L.

The sixth tab, Test Edit [CTRL+6], will allow you to enter test values for the fields used in the edit and run those test values against the edit logic. To enter test values, highlight the field name and press Enter or double click on the field name. Enter the test values in the pop-up dialog box and press Enter. Initiate the test by clicking on the TEST button on the form or in the toolbar. The program will display any returned messages in the message window, either if the data passed the edit, or if it failed, the error message from the edit logic. The CLEAR button will clear the message window. The Debug button will allow you to display the Edit Logic according to how it executed (see Debugging an Edit discussion). The Layout Button will check a record layout to verify that all of the fields in the edit are present in the layout. It will pop up a dialog box for you to specify which record layout to use.

Debugging an Edit

When you have run a test of your edit, you can evaluate precisely what happened by pressing the Debug button down. This will open a resizable window containing the edit logic according to how it executed:

The Variables pane lists all of the variables that have been declared as of the currently highlighted line of code. In the example above, that means all of the variables are listed. The useful part of this feature is that the value of each variable is reported as of each line of code. As you move up and down in the Debug Logic window, you will see the values change.

The Debug Logic pane displays only the code that executed. For example, if either of the fields used in this edit had been empty, this pane would have stopped displaying at line 9. Whenever a condition is tested and not met, as happens with if, for and while loops, the code that is "jumped over" is displayed in gray. If you highlight one of those lines you will see that the variables pane is emptied; there is nothing to report for non-executed lines.

The Edit Debugger is indispensable to testing your edits and understanding edits written by others.

A companion program, the EDITS Runtime Debugger (EditDebugger.exe), is installed with EditWriter. It provides this same level of information and more when running batches of edits against data files, such as those you would submit to GenEDITS Plus. Refer to the help file in the EditDebugger folder for more information.

Tiled Windows

On the Description, Logic, and Administrative Notes tabs, you can click on the "Tile" button to open a second window to display, for example, the Edit Description next to the Edit Logic while you are working on the logic. Choose the content for the tiled window from the drop-down box at the top. You may resize the two windows by clicking on the separator bar and holding down the left button on the mouse while you drag the window to a new size.

LogicWriter


Logic Writer

Within the Edit Object Workspace form, there are a number of tools to help write edit logic in the EDITS Language.

There are menus and buttons to assist in adding functions, constants, language constructions, data field names, user table names, and messages to the logic. The toolbar buttons are only available when the focus is on the logic pane of the Edit Object form. The popup menu is displayed by right-clicking in the logic window or by pressing F2.

The EditWriter will display a list of possible items to paste into the Logic Pane. By double clicking on a selection or highlighting and clicking [OK], the program will paste the selection into the Logic Pane.

Syntax Checker

When the focus is on the Logic Pane, the Syntax Checker toolbar button [image] is enabled. Click it to verify the validity of your Edit Logic:

If there are any syntax errors, they will be displayed in the message area below the Logic Pane. Double-click on the line, and the highlight bar will position you in the Logic Pane.

Record Layout Checker

While the focus is on the Logic Pane, the Record Layout Checker toolbar button [image] is enabled. Click it to check that all fields referenced by your Edit exist in the Record Layout you intend to run this against.

Select your layout, and click the [OK] button. When the checker has finished, it will display a message with the results:

Note: The Edits Engine will skip any Edits that reference fields that are not in your intended Record Layout. This verification can also be run for an entire Edit Set. Refer to the Edit Set Workspace Form.

Toolbars and Buttons


Edit Set Workspace Form

When you open an Edit Set object, the Edit Set Workspace Form opens with two columns of Edit Object names. The right column is the list of Edit names in the Edit Set, the column on the left is a list of Edit names which have not been added to the Edit Set.

The form also displays the Edit Set name, the description of the Edit Set, and the agency owner. With permission, you may modify any of these attributes. As of version 4 of EditWriter and the Engine, the edit set description can be retrieved from the runtime metafile. Refer to the EDITS API Documentation for details (topic EEx_GetEditSetDescript).

To move an Edit into the Edit Set, highlight the Edit name in the left column and

  • click on the right arrow, or

  • press CTRL+right arrow.

The moved Edit will be immediately inserted in alphabetic order into the Edit Set.

To move multiple Edits into the Edit Set, you may highlight more than one Edit with CTRL+Click or CTRL+Click with the mouse. Clicking the right arrow or pressing CTRL+right arrow will move all of the highlighted Edits into the Edit Set.

Hint: If you want to shorten the list of available Edits to add to the Edit Set, you may filter the Edits in the Navigator (e.g., recently changed) and click "Filtered" at the bottom of the window where it says "Apply Edits Navigator Filter."

Edits may be removed from the Edit Set in the same manner with the left arrow. Removed Edits will added back to the list of unassigned Edit names on the left.

As Edits are moved from one side to the other, their names turn red and will stay red until the Edit Set is saved.

To search for an Edit by name in either column, begin typing the name in the list you are searching. The letters you type will be echoed in the dialog box above the list. To clear text from the search box, press [Escape].

You may open an Edit from the Edit Set by highlighting its name, then

  • clicking on the LAUNCH button [image], or

  • selecting "Launch" from the Edit Set menu, or

  • pressing CTRL+L, or

  • dragging the Edit name onto the workspace.

Creating New Objects

Deleting Objects


Field Workspace Form

Opening a Data Field Object will display its attributes in a Field Workspace Form with three panes: description, edits, and layout. To move to another pane, click on the tab at the bottom, select the pane from the field menu, or press CTRL+n. Attributes may be modified depending upon password permissions.

At the upper left of the Description pane, the standard attributes (Number, Name, Type, and Length) are displayed. At the upper right, the local attributes are displayed (Number, Name, and Title).

To change or assign an Agency Code, select the new code from the drop-down box. You must be logged in as the owner of the object to modify the standard attributes or the local number. Please refer to the discussion on the Known Problems page concerning how the Engine treats the Local Number.

The description window is a free text attribute that may be used for any notes about the field and its usage.

Selecting the Edits pane will change the bottom of the form to a listing of Edits which reference the data field object. An Edit may be launched from this pane by dragging its name onto the workspace or by highlighting the name and pressing the Launch button [image].

Selecting the Layouts page will swap in a list of the Record Layouts that contain the data field object. A Record Layout may be launched from this pane by dragging its name onto the workspace or by highlighting the name and pressing the Launch button [image].

Creating New Objects

Deleting Objects


Record Layout Workspace Form

When you open a Record Layout Object, the workspace form opens with two windows of Data Field Object names. The pane on the right is the Record Layout, the pane on the left is a list of field names which are not included in the layout.

The form also displays the layout name, the description of the layout, and the agency owner. With permission, you may modify any of these attributes. As of version 4 of EditWriter and the Engine, the layout description can be retrieved from the runtime metafile. Refer to the EDITS API Documentation for details (topic EEx_GetRecordLayoutDescript).

To insert a Field into the Record Layout, highlight the Field name and click on the right arrow. Moving a Field will prompt the user to insert the Field into the Record Layout either before or after the current position (as indicated by clicking on a field in the layout) or at the beginning or end of the record. If you remove the check mark from the "Ask for insertion point" box, the prompt will not appear the next time you insert a field, but will use the same instructions as checked in the prompt at that time. To display the prompt, press CTRL+O.

You may also create an "overlay" effect where one field starts in the same position in the Record Layout as another (e.g., Histology and Morphology--Histology/Behavior) by removing the check mark from the "Adjust start positions" box. You may also create the same effect by typing over the start position in the right column.

Caution: sometimes manual intervention (re-entering the column position) may be required to get fields back into the correct locations when removing an "overlay" field.

To move multiple Fields into the Record Layout, you may highlight more than one Field with Control+Click or Shift+Click. Clicking the right arrow will move all of the highlighted Fields into the Record Layout in the same order.

You may change the sort order of the Fields in the Record Layout by clicking on the column headings of the list. Note, however, that the list must be sorted by the first column (Pos, for "starting position in the layout") in order to add a field to the layout. This is because the starting position of all fields following a newly added field (or group of fields) must be recalculated, a task that is tricky enough without the list being out of order.

The lists support incremental searching, based upon the currently selected sort order. For the Fields in the Data Dictionary list, the only sort order is Standard Name. For the Fields in this Record Layout list, the sort orders are Starting Position, Standard Name, Local Type and Field Length. To locate a field in either list, give focus to the list (e.g., click on it with the mouse) and begin typing. Your keystrokes will be echoed in the area above the list, and the highlight bar will reposition to find the first Field that matches what you have typed.

Fields may be removed from the Record Layout by highlighting the Field name or names in the right pane and clicking on the left arrow. Removed Fields will be added back to the list of unassigned Field names on the left.

Fields may be moved up or down in the Record Layout by highlighting the Field name and clicking on the up or down arrows.

Save any changes to the Record Layout by clicking on the [Save] button. To discard changes without saving, click the [Close] button. You will be asked if you want to save your changes; answer [Yes] to save, [No] to discard, or [Cancel] to resume editing.

Creating New Objects

Deleting Objects


Message Workspace Form

Opening a message from the Message List will display its attributes in a Message Workspace Form where they can be modified.

The Message Workspace Form will also display a list of edits for which this Message is the default error message. An edit may be launched from this list.

Message Format Specifiers

Messages can be used in multiple edits. Yet to keep them informative, it is best to provide information about the fields that were involved.

Message Format Specifiers are placeholders in an error message, with the following meanings:

Specifier | Meaning
%F1..%Fn | Title for Field 1 through Field [n]
%V1..%Vn | Value of Field 1 through Field [n]
%D1..%Dn | Value of Date Field 1 through Date Field [n]

The position number for these specifiers is established on the Edit Workspace Form:

This Edit references two fields. This page lets you rearrange the order of the fields so that the displayed message makes sense.

For Date fields, the %Dn specifier provides a clear breakdown of the parts of the date (Y:0000 M:00 D:00):

Output might look like this:

Creating New Objects

Deleting Objects


User Table Workspace Form

There are three types of tables in a Metafile: DBF, ASC, and BIN. The program recognizes each type of table and opens a window specific to the type of table being opened.

Because ASC and BIN tables have largely fallen out of use, EditWriter does not allow these table types to be created, but still supports import of existing tables and their use within Edits.

There are three tabbed panes to the Table Workspace form: Table (CTRL+1), Properties (CTRL+2), and Edits (CTRL+3).

DBF Table

Note: It is possible to retrieve values from user tables within EDITS. Refer to LOOKUP Functions and User Tables for details.

For a DBF table, the Table pane will open the table in tabular form to allow for viewing and editing. The Properties pane lists the Table name, description, agency, record size, record count, date last modified, index order, structure, and the contents of the table. The Edits pane lists the Edits that use the Table and that may be opened with the "Launch" menu selection, the "Launch" button [image], or dragging the Edit name onto the workspace.

To locate a specific record, you may scroll up and down, search (CTRL+F) for it with an index, or "go to" a record by pressing CTRL+G and entering the record number (or top or bottom).

To modify a record, highlight it and click on the [Edit Record] button. A new dialog window will open and allow you to enter new values for each of the table fields. After you click [OK], the record will be displayed in red text to show that it has been changed.

To add a new record to the end of the table, click on the [Append Record] button. The dialog window will open to allow you to enter values for each table field. After you click [OK], the new record will be displayed in red text to show that it has been changed.

To copy an existing record in the table, highlight the record and click on the [Copy Record] button. The marked record will be copied to the end of the table and be displayed in red text. You may now edit this record to change the values if you wish. The program will not prevent you from saving a duplicate record in the table, even if indexed.

To mark a record for deletion, highlight the record and click on the [Toggle Delete] button. This marks the record as deleted but does not actually remove it from the table. Until you pack the table, the record will physically remain in the table and may be restored by clicking on the [Toggle Delete] button again. The marked record is shown in gray italics.

DBF Index Maintenance

The Properties pane also allows you to change the sort order for the records in the table by a defined index. Choose the sort order you want from the drop-down selection of indices or "natural order" to view the records in the order they were entered into the table.

You can also search a DBF Table by selecting the index ordering and pressing CTRL+F to open a dialog box. Enter the text string into the dialog box and press [OK]. Note: you may search only for strings that begin with the string you enter.

To create an index, select Index Maintenance from the Table menu. The Index Maintenance dialog box opens to allow you to define multiple indices for the table. The top area shows all existing indices. To remove an index, highlight it and click the [Delete] button.

To define a new index, use the Expression Builder. Give your new index a name (e.g., "SITE") by typing it into the Index Name box. You can type directly into the box or copy field names or functions from the lists below. The simplest indices are a single field (e.g., "CountyCode") or two concatenated fields (e.g., "CountyCode + City"). For more complicated indices, you may use any of the fields solo or in combinations with any of the functions. Before saving your expression, you can validate it by clicking on the [Verify] button. If the function is valid, you may [Add] it to the list of index names listed at the top. When you have finished, click [OK] to save, [Cancel] to close the Expression Builder without saving.

Restructure Table

You may change the structure of a table by adding new columns or renaming or deleting columns. Select Restructure Table from the Table Menu.

To add a new column, enter the name of the column in the left box at the bottom of the dialog box. Select the data type (character, date, or numeric) from the dropdown list in the center box, and enter the width of the data in the column (date types are fixed at 8). Click [Save] to move the column into the table. If you do not want to add the column, click on an existing column or on the [Cancel] button.

To rename or redefine an existing column, highlight the column name and its properties will appear in the boxes at the bottom. Make the changes you want and click [Save] to fix them in the table.

To delete a column, highlight the column name and click the [Delete] button.

To change the order of columns in the table, click the up and down arrows on the right.

After making all of the changes, click [OK] to save them; click [Cancel] to discard all changes.

Pack Table

If you do a lot of maintenance on a table, especially deleting records, the structure of a table may become somewhat inefficient and indices may become corrupted. To remove deleted records and otherwise maintain the health of your table, you can pack it by selecting Pack Table from the Table Menu.

Zap Table

Sometimes you may want to completely replace the contents of a table, but without deleting its structure because you want to repopulate it from a new source file. To delete all records from a table, select Zap Table from the Table Menu.

Append from ASCII File

To add new records to an existing table, or to replace records in a zapped table, select Append From ASCII File from the Table Menu. The program will open a select file dialog box for you to identify the source of new records. The source file must have all fields delimited by quotation marks and separated by commas, and the fields must be in the same order as the columns in the table.

ASC Table

For an ASC table, the Table pane will open the table in a text editor window. The Properties pane is similar to that for the DBF table, except that there is no structure to the table. The Edits pane is the same as for the DBF table.

BIN Table

For a BIN table, the Table pane displays the table contents, but will not allow editing. The Properties pane lists Table name, description, agency, number of cells, columns, rows, date last modified, and structure. The Edits pane is the same as for the other two tables.

Editing a BIN table will require the Binary Table Tool (BTT) program used with EditWriter 2.

Creating New Objects

Deleting Objects


Creating New Objects

New Metafile objects may be created in three different ways:

  • Add - Select "Add" from the Toolbar menu, click the Add Object button [image], or press CTRL-Insert while on the Navigator pane for that type of object. The object must be saved under a unique name and/or number.

  • Copy - Select "Copy" from the Toolbar menu or click the Copy Object button [image] while highlighting the object name to be copied. The object must be saved under a new and unique name and/or number.

  • Save As - Select "Save As" from the Toolbar menu or click the Save As button [image] while the workspace form is open for the object to be copied. The object name must have been changed to a new and unique name and/or number.


Deleting Objects

Metafile objects may be deleted from the Navigator lists. Highlight the name of the object to be deleted and select "Delete" from the toolbar menu, click on the Delete Object button [image], or press CTRL+Delete.

There is no "undo" for deleting objects except to close the Metafile without saving the changes.


Importing Objects

You may copy objects from one Metafile to another with the Import process. To begin the Import process, select "Import Metafile" from the Tools Menu. EditWriter will prompt for the name of the "Source" Metafile (which contains the objects you want to bring into the open "Target" Metafile).

Hint: It is not necessary to convert a version 2 Metafile to version 3 in order to import objects from a version 2 Source Metafile, but if you will be using that Source Metafile repeatedly, you will save some time by first converting and saving the Source Metafile to version 3.

Next, the program will allow you to filter which types of objects to import.

To list all objects in the Source Metafile, all of the boxes should be checked. To select only certain types of objects, check only those boxes. Clicking on the red check mark will toggle all of the boxes.

Hint: usually there are more edits than any other type of object, so listing new and changed edits takes the most time in the first step of the Import process. If you are only importing tables, for example, unchecking all of the other objects will speed up the listing.

Hint: if you plan to import more than one kind of object, you can check all of the kinds you want, but you can filter them again later in the process without the program having to recompare the objects.

If the box to include Date Modified in comparison between the Metafiles is unchecked, the EditWriter will ignore objects that are identical between the Source Metafile and the Target Metafile except for the date the object was last changed.

If you know that you only want to import a few specific objects, you can further speed up the processing by checking the box to "Let me choose." For example, if you maintain a few specific edits and tables in your own customized Metafile but otherwise want to use the edits and tables in the newest NAACCR Metafile, you can eliminate the evaluation of most of the edits and tables between the Metafiles. If this box is checked, the program will display the objects in the Source Metafile and allow you to specify which ones to import by double-clicking on the object names. The selected objects will be displayed as highlighted object names preceded by ">>." The program will now compare only these objects between the Source and Target Metafiles. If they are unchanged, they will not be displayed in the Import dialog.

After you click [OK], EditWriter will compare the objects in the Source Metafile with those in the Target Metafile and display them in a two-column list. At the top of the Import dialog box, the program lists the options you selected. You may change the filtering at this time to look at only one type of object at once, or exclude certain types of objects, without going through the comparison step again. You may also look only at new objects or only at changed objects or both.

If you interrupt the evaluation process, the program will stop and show you just the objects that have been compared and found to be different between the two Metafiles. You may continue with the import process with the displayed objects as below, or you may exit the process by clicking [Close].

At the bottom of the dialog box, EditWriter lists the Source objects in the left column with status either NEW (not present in the Target Metafile) or CHG (present in the Target Metafile, but different from the Source object). You may toggle among showing new objects, changed objects, or both without re-evaluating them.

Between the two columns are some buttons to help you with the process:

  • [Right Arrow] - moves objects into the right column to be imported

  • [Left Arrow] - moves objects out of the right column, removing them from the import list

  • [Diff] - compares changed objects, objects which are different between the two metafiles, to see what the differences are

  • [View] - displays the attributes of an object in NotePad

ExamDiff®, a freely available program, is recommended (but not required) to show in detail the differences between objects. You must download this program from the http://www.prestosoft.com web site. If you wish to take advantage of the complete power of ExamDiff, you may purchase a license for the program from the web site.

You may use another diff tool in place of ExamDiff. The first time you click the [Diff] button, EditWriter searches for a diff tool. If it does not find one, it will allow you to browse your system to identify another diff tool. Once found, EditWriter will record the name and path for future use.

The following paragraph and image describe the experience when using ExamDiff; if you use another diff tool, some attributes may be different.

To view the line-by-line changes in an object between the import object and the target object, click on the [Diff] button. Differences between the objects are highlighted in different colors (you may select the colors to display each difference: added, deleted, or changed). This tool allows you to see the exact changes between objects before you select the Source object to import and overwrite the Target object.

To view an object (either changed or new), highlight the object name in the Source list and click on the [View] button.

Selecting Objects to Import

To begin importing objects into the Target Metafile, you must move them from the left list to the right list by highlighting the object name by clicking the left mouse button, then clicking the [Right Arrow] button. You may highlight multiple objects with [Control]+click or [Shift]+click; all of the highlighted objects will be moved to the right or Selected column.

At this point, none of the objects have actually been imported into the Metafile. If you change your mind, you may remove objects from the Selected list by highlighting them again and clicking the [Left Arrow] button. If you decide not to import the selected objects, you may click the [Close] button at the bottom of the window.

Logging the Import Process

EditWriter records the import process in a log file, listing each object that you import and any dependency conflicts that may require additional attention. This log file is named for the Target Metafile with the file extension .LOG. It may be viewed with any text editor, such as NotePad.

If an existing log is found at the start of the import process, the program will ask you if you want to append the current log to the previous one. Click [Yes] to keep the existing log and add new transactions; click [No] to erase the old log and start a new one.

Importing Selected Objects

To complete importing the selected objects, click the [Import] button at the bottom of the window. To stop the import process, click the [Stop Import] button.

A "changed" Source object will be displayed first in Conflict Resolution dialog window to give you choices about what to do next. Click on the action that you want to happen for this object.

  • Replace the like named object in the Target Metafile

  • Rename the object in the Target Metafile and import the Source object under the old name

  • Rename the Source object (so that it doesn't overwrite the Target object) and import it

  • Skip importing the Source object.

Once again, you may use the [Diff] button to compare the two objects before you proceed.

If a Source object has "dependencies" - other objects associated with it, such as Data Fields, Error Messages, or Tables - you may choose at this point to import those dependencies (if changed), even if you haven't selected to import them already, or you may choose not to import them at this time. See Importing Dependencies.

A "new" Source object will be imported into the Target Metafile automatically when you begin importing the selected objects, unless there are "dependencies" already in the Target Metafile, but different between the Source and Target Metafiles. See Importing Dependencies.

To import the object now, click on the [OK] button. To stop the import process, click on the [Stop] button.

Importing Dependencies

If a selected object contains other objects (e.g., Data Fields, Error Messages, or Tables within an Edit or Edits within an Edit Set), there may be differences between these "dependent" objects in the two Metafiles. EditWriter will notify you when these objects differ and display them in a Conflict Resolution dialog window.

Save Your Work

After completing the import process, you should save your work by clicking the [Save] or [Save As] button on the tool bar, or by selecting Save or Save As from the File Menu. If you do not wish to save the imported objects, you may close the Metafile without saving.


Reports

EditWriter allows you to view or print out reports for individual objects as well as lists of collected objects. Reports are presented in a preview form, from which you can browse, print the contents, or save them to a file. Reports are saved in Rich Text Format (.rtf), which can be opened by most word processing software.

List Reports

List reports allow you to view or print reports on multiple objects. You can view reports on all objects in the Navigation list, or you can print subsets. Create subsets by highlighting the names of the objects to print or by applying a filter.

Select the report you want by selecting it from the Reports menu at the top of the window, then indicate whether you want the report to include all objects in the Navigator list or only the selected (highlighted) ones. You can also produce the report as a continuous list or with each new object at the top of a new page.

Reports for Field Objects and Edit Objects allow you to customize the output by printing only some of the attributes. Click those attributes that you want included. For Field Objects, the selections are Description, Record Layout, and Edits. For Edit Objects, the selections are Edit Sets, Fields, Tables, Messages, Description, Administrative Notes, and Edit Logic. For both reports, there is an option to print a single line report, the object name.

Individual Reports

You can print a report for an object in the active workspace form by pressing the Report Object button from the tool bar.

Viewing Reports

After the program formats the report, it will open a window in the workspace to display it. The toolbar at the bottom of the report window will allow you to:

Zoom in (make the report larger onscreen)

Zoom out (make the report smaller onscreen)

Full screen (expand the report to fill the report window)

Fit screen (display a full page in the report window)

Go to the first page

Go to the last page

Go to the previous page

Go to the next page

Print the report

Save the report

Close the report window

Edits/Edit Set Comparison Report

This edit allows you to compare two or more Edit Sets to see which Edits are in each. To view this report, select "Excel: Edits/Edit Sets" from the Reports Menu. You can select the Edit Sets to compare, or include all of them.

The program will ask you for the name of the CSV report file that will be created and sent to Excel. If that file already exists, it will ask if you want to overwrite it. The report will open in Excel, where you can modify it and print or save it.


Known Problems

The issues below are known problems with the EditWriter.

Backward Compatibility

Once a Metafile is opened and saved in the current version format, it cannot be reopened by EditWriter 2.0 and the runtime Metafile compiled by EditWriter cannot be run with GenEdits (DOS version). There are no plans to change this (those DOS tools are obsolete).

Error Correction Help and Administrative Notes

There is a 10,000-character limit (by the Edit Engine) for error correction help (formerly known as description) and administrative notes (formerly known as error correction help). If text in either of these attributes is longer than 10,000 characters, the Edit Engine will not return it to the calling program. This issue is in the list of identified problems in the Edit Engine.

String Length in Edit Logic

There is a 79-character limit on how long a text string may be brought into the edit logic: attempting to verify that a string longer than 79 characters is empty will always fail. This issue is in the list of identified problems in the Edit Engine.

Syntax Checker/Compiler

It may be possible to write an operation in edit logic that would send the syntax checker/compiler into an infinite loop. It would be nice to have a way of cancelling the operation short of invoking the Windows Task Manager with CTRL+ALT+DEL and killing the process. But if it is necessary to kill the process with Task Manager, the temporary files can be reattached by reopening the Metafile, recovering all saved work. If you encounter this problem, please send to Technical Support the edit logic that made it happen. (We have not encountered this in any release version of EditWriter; but we would be foolish to think it could not happen.)

Edit Sets

Appending one Edit Set to another is not a reversible action; the [Save] button does not become enabled because the appending process is automatically saved. The only way to undo an Edit Set append is to close the Metafile without saving the changes.

Tables

EditWriter cannot yet print the entire contents of a User Table object. You can print up to 100 records from a table.

The contents of a DBF table can be searched only by indices; strings that do not appear at the beginning of an indexed field in the table will not be found.

DBF tables may not be imported (other than from another Metafile), but must be defined and filled either by entering data or importing data from an ASCII file (see below).

The command "Append from ASCII File" requires a very specific input format: fields must be delimited by quotation marks and separated by commas.

There is no current function for exporting a DBF table. You may copy a DBF table to another location while the Metafile is open in EditWriter: under the Library subfolder (under the folder where you have installed EditWriter), you will see a folder with the same name as the Metafile; all of the User Tables are listed here. Select the table you want and COPY it to another folder. If you MOVE the table out of this subfolder, the integrity of the Metafile will be corrupted.

ASC (ASCII) and BIN (binary) tables have largely fallen out of common use. The existing tables may be imported from a version 2 metafile, but cannot be created or modified in EditWriter.

The LOOKUP() function in Edit Logic assumes that you have an unindexed table; if it is indexed, the Edit Engine will attempt to search the index instead of the actual table. If the name of the index is different from the name of the table column, the search will always fail even if the function specifies the column name in the table. If the table is indexed, use ILOOKUP() instead of LOOKUP().

Import

Agency is not considered a dependency of other objects and will not be imported as a dependency when objects "owned" by the agency are imported.

When importing a Field object, the matching is done on the Local Number, not on the Standard Number as you might expect. This is due to a peculiarity of the EDITS Engine: Although Field objects have always been documented to allow users other than the owner of the object to modify the Local fields, the Engine uses the Local Number to identify fields referenced in edits and record layouts. Thus, a seemingly innocuous change can break a Field object and everything that uses it. As of v4.0.0.5 of EditWriter, you must be logged in as the owner of the Field Object to change the Local Number; you may, however, change the Local Name and/or the Title of the Field object without being logged in as the owner.

Network Operation

EditWriter will operate from a network drive, but it requires permission to create temporary working folders and working files in order to do so, as well as permission to delete the temporary folders and files after closing a Metafile.

Performance is much better when the EditWriter program files are installed on the user's computer. Metafiles may be stored and maintained on the network to allow automated backup procedures to protect your work. Under this configuration (i.e., with EditWriter on the user's computer and the Metafiles on the network), no special permissions are required for creating and deleting temporary files and folders. However, the user will require the rights to access, read and write to the Metafile, of course.


Writing Edits: Using the EDITS Language

 | The EDITS Language section defines the EDITS programming language as implemented by EditWriter and the EDITS Engine.
Introduction | The EDITS language provides basic control structures, variable declaration, and a library of functions for data comparison, string operations, and other generic computing tasks. These functions have their roots in a variety of languages including C, Basic, and xBase.
Structure of an Edit | An edit can contain declarations for local variables, as well as expressions and statements. Execution of an edit always starts at the first line.
Comments | Comments enclosed in the symbols /* and */ should be used to explain and annotate edit logic.
Declarations | All variables must be declared before use. The variable "type" determines what kind of data (numeric or character) can be stored. Variables can be given an initial value during declaration.


Using the EDITS Language

EDITS Application Fields

Data fields to be edited are defined in the Data Dictionary section of the Metafile and organized in the Record Layout section. These fields do not have to be declared in order to use them in an edit. Unlike variables, they already exist if properly initialized. The notation for referencing data fields is described as follows:

All references to a data field begin with a pound sign (#). The next character will be an S or L, denoting whether the field name that follows is the Standard name or Local name for that field. The field name is enclosed in double quotes ("), as field names can contain spaces and other punctuation. Here are some examples:

Standard Name: "Sex" Local Name: "Gender"

Referenced as: #S"Sex" Referenced as: #L"Gender"

Edits can be written using either standard or local names. The View buttons can be used to switch view of an edit between standard and local names.


Writing Edits:

Using the EDITS Language

Data Types In EDITS

The EDITS language uses four keywords to specify data types: int, long, char, and tablevar.

Int and long are identical in the EDITS language.

Strings are allocated as arrays of char.

Tablevar is used to retrieve values from a field in a DBF lookup table. Each tablevar declaration matches the name of a field in the DBF. Following a successful call to a lookup function (LOOKUP, RLOOKUP), the table is aligned on a record in that table, and the contents of the fields in the record can be accessed through the tablevar. Refer to Example Edits and to LOOKUP Functions and User Tables.


Expressions

Writing Edits:

Using the EDITS Language

Expressions In EDITS

EDITS expressions may contain a combination of variables, constants, function calls, and operators which result in a single value. The following is a summary of available operators.


EDITS Operators

 | Operator | Name | Example | Precedence (1=highest)
Arithmetic Operators | * | Multiplication | x*y | 3
 | / | Division | x/y | 3
 | % | Modulus | x%y | 3
 | + | Addition | x+y | 4
 | - | Subtraction | x-y | 4
 | - | Negation | -x | 2
Relational Operators | > | Greater than | x>y | 5
 | >= | Greater than or equal to | x>=y | 5
 | < | Less than | x<y | 5
 | <= | Less than or equal to | x<=y | 5
 | == | Equal to | x==y | 6
 | != | Not equal to | x!=y | 6
Logical Operators | NOT | Logical NOT | NOT x | 2
 | AND | Logical AND | x AND y | 7
 | OR | Logical OR | x OR y | 8
Assignment Operator | = | Assignment | x=y | 9
Miscellaneous Operators | [ ] | Array element | x[0] | 1
 | () | Parentheses for function call, Evaluate first | f(x) x * (y+z) | 1
 | * | Indirection | *p | 2


Statements in EDITS

 | Statements in the EDITS language may assign values, call functions, return values, or otherwise control the flow of execution. Each statement must end with a semicolon. Statements can be combined into compound statements (or blocks) following an "if" statement or, "while", "do..while" or "for" loops by placing a pair of braces ({...}) around the statements. If only one statement is to be executed after a block, then no braces are required. If more than one statement is needed after a condition, enclose those statements in a pair of braces. Keywords, variables, and functions are all case-insensitive. Here is a summary of statements by keyword:
Assignment statement | variable = expression The variable receives the value of the expression.
Example | i=0;
If statement | if(expr1) <statement1> [else <statement2>] expr1 is evaluated. If TRUE, statement1 is executed. If false, the optional else clause and statement2 are executed, if present.
Example | if(y!=0) q=x / y; else q=0;
For loop | for(initialize;test;increment) <statements> The initialization is done once. Test is evaluated before each iteration through the loop; if true, the statements are executed. The increment expression is performed after each execution of the statements, but before the next test.
Example | for(i=0;i<10;i=i+1) myarray[i]=0;
While loop | while(<condition>) <statements> condition is evaluated before each iteration through the loop; if true, the statements are executed.
Example | int t_row; char t_output[4]; t_row = 0; /* will execute 3 times, then exit loop */ while (t_row < 3) { fmtstr(t_output, "%ld", t_row); save_text(t_output); t_row = t_row +1; }
Do..while loop | do { <statements> } while ( <condition> ) statements execute at least once before condition is tested. Then, condition is evaluated before each subsequent iteration through the loop; if true, the statements continue to be executed.
Example | int t_row; char t_output[4]; t_row = 4; /* will execute once, then exit loop */ do { fmtstr(t_output, "%ld", t_row); save_text(t_output); t_row = t_row +1; } while (t_row < 3);
Return statement | Return expr Exits the edit, with a return value of expr.
Example | Return FAIL;


Example Edits

Check field "Clinical Breast Exam" against 1,2,3, or 4Example Edits

If(INLIST(#S"Clinical Breast Exam", "1,2,3,4")

==TRUE)

return PASS;

Else

return FAIL;

Notes: Inlist returns TRUE or FALSE, which has the same ordinal value as PASS or FAIL. This edit could be reduced by removing the check for Inlist returning TRUE, as the result of the assignment is also TRUE or FALSE:

If(INLIST(#S"Clinical Breast Exam","1,2,3,4"))

return PASS;

Else

return FAIL;

Since we only return PASS if the Inlist is TRUE or FAIL, if it is FALSE, we could further reduce the edit by eliminating the If and simply returning the return value from Inlist:

Return INLIST(#S"Clinical Breast Exam", "1,2,3,4");

The last edit occupies less space and runs slightly faster; however, it is also slightly less readable. Inlist also accepts ranges of numbers, so this edit could be written as:

Return INLIST(#S"Clinical Breast Exam", "1-4");

Use keyword tablevar to retrieve a value from a lookup table

/* Table StateZip.dbf consists of three fields.

* Declare TABLEVARs for the fields in this lookup table

* that will be referenced in this edit.

*/

tablevar STATE, ZIPLOW, ZIPHIGH;

/* Declare concatenated state/zip variable */

char StateZip[20];

/* Declare a message variable */

char show_msg[50];

/* Concatenate State, Zip */

strcpy(StateZip,#S"Addr at DX--State");

strcat(StateZip,#S"Addr at DX--Postal Code",5);

/* Look up closest record >= search key */

if(RLOOKUP(StateZip,"StateZip.DBF.ST_ZIPLOW"))

{

/* If found, confirm it's correct */

if (strcmp(#S"Addr at DX--State",STATE)==0 &&

strcmp(#S"Addr at DX--Postal Code",ZIPLOW,5)>=0 &&

strcmp(#S"Addr at DX--Postal Code",ZIPHIGH,5)<=0)

{

strcpy(show_msg, StateZip);

strcat(show_msg, " falls between ");

strcat(show_msg, ZIPLOW);

strcat(show_msg, " and ");

strcat(show_msg, ZIPHIGH);

/* show_msg looks like:

* "CA94564 falls between 90000 and 96199"

*/

SAVE_TEXT(show_msg);

return PASS;

}

else

return WARN;

}

return FAIL;

Check field "CBE Date" against "Clinical Breast Exam"

If(INLIST(#S"Clinical Breast Exam", "1,2"))

Return not EMPTY(#S"CBE Date");

Else

Return EMPTY(#S"CBE Date");


LOOKUP Functions and User Tables

Three EDITS Language functions exist for finding data in User Tables; they are: RLOOKUP, LOOKUP and ILOOKUP. Knowing which function to use requires some analysis.

LOOKUP vs. ILOOKUP

When you are searching for an exact match for your criteria, the decision process looks like this:

Note: There is no good reason to perform an unindexed search on a DBF table. The overhead for maintaining one or more indexes on a table is negligible, and the benefits are measurable. If you need an index, create one!

Notice the question: Do you need to retrieve values from the found record? The LOOKUP function retrieves the values from the current record into TABLEVARs (see below); the ILOOKUP function does not. There is a small performance consideration for making these values available, so if you don't need them, go with the peppier ILOOKUP.

RLOOKUP

When you are searching for a close match, e.g., to determine whether a value falls within a range defined by two fields in a DBF table, use RLOOKUP.

This function retrieves the values from the current record into TABLEVARs, just as LOOKUP does (see below). In the case of RLOOKUP, it is essential that you compare these values to the search criteria. This function will stop searching when it finds the record with the highest value that is less than or equal to the search criteria, which could be a record that falls completely outside the range you are seeking. Refer to the code example for RLOOKUP for details.

TABLEVARs in Excruciating Detail

We will rework a simple edit to demonstrate how TABLEVARs are created and used.

RLOOKUP and TABLEVARs

Consider this edit:

The tablevar declaration lists the fields in StateZip.DBF which will be referenced in this edit.

The call to RLOOKUP performs an indexed search (the second parameter includes the name of the index tag, ST_ZIPLOW).

The only way RLOOKUP could return FAIL is if the search criteria is lower than the lowest key in this table (including an empty string). However, just because RLOOKUP finds a record doesn't mean it found the record that confirms the search criteria. Consider these examples, shown in the test bench debugger:

Criteria Falls Within Range

The Variables window displays the contents of the fields in the record found by RLOOKUP. The STATE value matches the data field Addr at DX--State, and the data field Addr at DX--Postal Code falls between ZIPLOW and ZIPHIGH.

Criteria Falls Outside Range

This time, RLOOKUP found a record, but the comparison of ZIPHIGH to the Addr at DX--Postal Code fails (the data field has a zip code that is higher than ZIPHIGH).

LOOKUP and TABLEVARs

Notice the changes to the edit:

The declaration of tablevars has been omitted (we'll explain in a moment).

The edit performs an indexed lookup seeking an exact match of the search criteria.

Criteria is Found (Exact Match on Indexed Search)

Here's how it looks in the debugger:

Hey! We didn't declare tablevars, so what are STATE, ZIPLOW and ZIPHIGH doing there?

When RLOOKUP or LOOKUP is invoked from an edit, the EDITS Engine declares variables for each field in the table, and updates the values of those variables to show the contents of the current record. This provides dandy feedback for debugging your edit, but if you want the edit to reference any of the fields, they will have to be declared as tablevars.

The index key ST_ZIPLOW is a concatenation of field STATE + ZIPLOW. This edit passed because the criteria exactly matched what is in the table.

Criteria Found (Exact Match, Unindexed Search)

LOOKUP accommodates searching for a value without using an index key, but it requires an exact match between the search criteria and the concatenation of all fields in the record... in the correct order! We don't recommend you do this, because it is much less efficient than indexed searches. But just to prove a point, here it is (code shown in the debugger only):

LOOKUP does not specify an index tag in the second parameter.

The search criteria must exactly match the entire contents of the record. If the order of the fields is changed, or if any part of any of the fields is missing or different, the LOOKUP will fail.

Criteria Not Found (Seeking Exact Match)

Using either of the above edits, if the LOOKUP fails, the Variables window will show empty values for the tablevars:

The LOOKUP failed, so the tablevars are blank.

ILOOKUP (no TABLEVARS)

And finally... ILOOKUP. Use this function when you don't need to access the data in the lookup table. This function is faster than LOOKUP because it does not have the overhead of creating and updating the tablevar variables.

We doubt whether you would ever be able to detect a performance difference between LOOKUP and ILOOKUP. (The Engine is very, very fast.) Still, when nanoseconds count, ILOOKUP will give you the best speed results.

Always designate an index key when using ILOOKUP.

Notice that no tablevars are created.


EDITS Language Reserved Words, Symbols and Constants

EDITS Language

Reserved Words, Symbols and Constants

D elimiters

Logical Operators

Arithmetic Operators

Relational Operators

Variable Declarations

Keywords, Constants

Predefined Constants


EDITS Language

Reserved Words, Symbols, and Constants

Delimiters

Symbol | Name, Meaning
" | String, Double Quote
#S"..." | Standard Field
#L"..." | Local Field
' | Character Constant, Single Quote
() | Parentheses
, | Comma
. | Period
: | Colon
; | Semicolon
[] | Brackets
{} | Braces


EDITS Language

Reserved Words, Symbols, and Constants

Logical Operators

The EDITS Language supports logical operators derived from XBase (And, Or, Not) and C (&&, ||, !) programming languages. They can be used interchangeably.

Symbols | Name, Meaning
And, && | Logical And
Or, || | Logical Or
Not, ! | Logical Not


EDITS Language

Reserved Words, Symbols, and Constants

Arithmetic Operators

Symbol | Name, Meaning
* | Multiplication
+ | Addition
- | Subtraction
/ | Division
% | Modulus


EDITS Language

Reserved Words, Symbols, and Constants

Relational Operators

Symbol | Name, Meaning
< | Less than
<= | Less than or equal to
= | Assignment
> | Greater than
>= | Greater than or equal to
== | Equality
!= | Inequality


EDITS Language

Reserved Words, Symbols, and Constants

Variable Declarations

Symbol | Name, Meaning
Char | Character and String
Int | Integers
Long | Integers (same as Int)
Tablevar | Table Variables (used like Char)


EDITS Language

Reserved Words, Symbols, and Constants

Keywords, Constructs

Symbol | Name, Meaning, Use
if | if(condition) statement [ else statement ]
else | else (see if)
while | while(condition) statement
do..while | do (statements) while(condition)
for | for(expr1;expr2;expr3)
return | return expr


EDITS Language

Reserved Words, Symbols, and Constants

Predefined Constants

Constant | Value | Meaning
PASS | 1 | Return on pass of edit.
FAIL | 0 | Return on failure of edit.
WARN | 2 | Return warning from edit.
TRUE | 1 | Return from Boolean Functions.
FALSE | 0 | Return from Boolean Functions.
RIGHT | 0 | Parameter to TRIM, JUSTIFY.
LEFT | 1 | Parameter to TRIM, JUSTIFY.
BOTH | 2 | Parameter to TRIM.
DT_TODAY | Today's Date | Today's Date (used for date comparisons).
DT_VALID | high sentinel value | Return from VALID_DATE, but not from VALID_DATE_IOP.
DT_MISSING | high sentinel value | Return from VALID_DATE, but not from VALID_DATE_IOP.
DT_ERROR | high sentinel value | Return from VALID_DATE, but not from VALID_DATE_IOP. May be returned from all other date IOP functions if they fail their internal date validation checks. Indicates to caller that Date Component value %DC has been set and can be recovered.
DT_UNKNOWN | high sentinel value | Unknown Date. May be returned from functions that take min/max flag DT_EXACT as a parameter where the month or day portion of one or more input dates is empty.
DT_EMPTY | high sentinel value | Returned from many date IOP functions when at least one input date is an empty string.
DT_DAY_EMPTY | high sentinel value | Returned from DATE_DAY_IOP when the day portion of the input date contains two blank spaces.
DT_MONTH_EMPTY | high sentinel value | Returned from DATE_MONTH_IOP when the month portion of the input date contains two blank spaces.
DT_MIN | 1 | Parameter to functions that compare dates.
DT_MAX | 2 | Parameter to functions that compare dates.
DT_EXACT | 3 | Parameter to functions that compare dates.


EDITS Language Functions

Functions Overview

Function Return Types

N=Numeric

C=Char String

B=Boolean

X=None

Functions by Class

Date Functions

Allow_future_date_IOP, Datecmp_IOP, Date_day_IOP, Date_month_IOP, Date_year_IOP, Daydiff_IOP, Dayinterval_IOP, Monthdiff_IOP, Monthinterval_IOP, Valid_date_IOP, Yeardiff_IOP, Yearinterval_IOP

String Functions

At, Empty, Fmtstr, Inlist, Justified, Left, Lower, Match, Right, Strcmp, Strcpy, Strcat, Strlen, Substr, Trim,

Val, Upper

Table Functions

Binlookup, Ilookup,

Lookup, Rlookup

Recoding Functions

Getfield, Putfield

Error Handling Functions

Error_Msg, Error_Text, Save_Error_Text, Save_Text, Save_Warning_Text, Set_Warning

System, Miscellaneous Functions

ExternalDLL, Getvar, Setvar, Usr1-Usr10

Alphabetic List of Functions
Name | Type | Description
Allow_future_date_IOP | X | Permits future dates to be evaluated
At | N | Finds position of substring in string
Binlookup | N | Performs binary table lookup
Datecmp_IOP | N | Compares two dates
Date_day_IOP | N | Returns day portion of date
Date_month_IOP | N | Returns month portion of date
Date_year_IOP | N | Returns year portion of date
Daydiff_IOP | N | Returns difference in days
Dayinterval_IOP | B | Is date within interval of days?
Empty | B | Is field empty?
Error_msg | B | Changes error message number
Error_text | B | Changes error message text
ExternalDLL | N | Calls functions in dynamic link libraries
Fmtstr | C | Formats numeric value into string
Getfield | C | Gets field value from record layout
Getvar | C | Gets value of common variable
Ilookup | N | Index‑only lookup of value
Inlist | B | Is value contained in a list?
Justified | B | Is value left or right justified?
Left | C | Returns left n characters of string
Lookup | B | Performs lookup by value on a table
Lower | C | Converts string to lower case
Match | B | Compares string via pattern match
Monthdiff_IOP | N | Returns difference in months
Monthinterval_IOP | B | Is date within interval of months?
NameExpr | C | Returns contents of named variable
Putfield | B | Replaces field value with new value
Right | C | Returns right n characters of string
Rlookup | B | Performs range lookup by value on table
Save_Error_Text | X | Generates error messages but does not set flags
Save_Text | X | Generates messages but does not set flags
Save_Warning_Text | X | Generates warning messages but does not set flags
Set_Warning | X | Generates warning messages and sets flags
Setvar | X | Set common variable
Strcat | C | Concatenates a string onto another
Strcmp | N | Compares two strings
Strcpy | C | Copies one string into another
Strlen | N | Returns length of a string
Substr | C | Returns a substring of a string
Trim | C | Trims leading and/or trailing blanks
Upper | C | Converts string to upper case
Usr1-Usr10 | N | Calls user-defined function
Val | N | Returns numeric value of string
Valid_date_IOP | N | Checks date for validity
Yeardiff_IOP | N | Returns difference in years
Yearinterval_IOP | B | Is date within interval of years?


Detailed Descriptions

ALLOW_FUTURE_DATE_IOP

Sets state flag in Engine for duration of EDIT to permit future dates to be evaluated.

Syntax

void ALLOW_FUTURE_DATE_IOP(years_into_future)

Description

Parameter years_into_future permits all date IOP functions called from within the same EDIT to use a date that may occur after the current system date.

Background: The (deprecated) VALID_DATE function has the undocumented behavior of declaring a date valid for up to five years past the current system date. As part of the support for 2010 data changes, it was decided to surface that behavior so that authors of edits can control how far into the future a date may be deemed valid.

At the start of each edit, the Engine will set a state flag to 0 (zero), meaning that a date cannot be later than the current system date.

ALLOW_FUTURE_DATE_IOP resets the state flag to the value of years_into_future for the duration of the edit or until ALLOW_FUTURE_DATE_IOP is called from the same edit to change the value again.

This feature is useful for edits that seek to validate treatment dates scheduled to occur in the future. It is also useful for testing EDITS designed to conform to rules that will be effective at a future time (e.g., edits written in 2009 for 2010 dates).

Return value

None

Example

int dtdiff;

char dateDx[9], datePlanned[9];

/* This EDIT refers to a non-NAACCR field, Date Radiation Planned.

* The goal is to ensure that treatment is planned to begin within

* a 3-month window from Date of Diagnosis. The expectation is that

* diagnosis occurred on or before the current system date, but that

* the planned date may be in the future.

*

* Allow for dates to occur in the future. This call provides a

* one-year window.

*/

ALLOW_FUTURE_DATE_IOP(1);

strcpy(dateDx, #S"Date of Diagnosis");

strcpy(datePlanned, #S"Date Radiation Planned");

dtdiff = MONTHDIFF_IOP(dateDx, datePlanned, DT_MAX);

/* ALWAYS check date IOP functions for error codes! */

if (dtdiff == DT_ERROR)

{

if (!VALID_DATE_IOP(dateDx))

error_text("Date of Diagnosis error: %DC");

else if (!VALID_DATE_IOP(datePlanned))

error_text("Date Radiation Planned error: %DC");

return FAIL;

}

else if (dtdiff == DT_EMPTY)

{

error_text("At least one of the dates is an empty string");

return FAIL;

}

if (dtdiff > 3)

{

error_text("Rx Planned should be within 3 months of Date Dx");

return FAIL;

}

return PASS;


Detailed Descriptions

AT

Use AT to find the position of a character expression within another character expression.
Syntax | AT(expC1, expC2 [, width])
Description | AT searches character expression expC2 for the first occurence of character expression expC1. If expC1 is found, it's position in expC2 is returned. If not found, zero is returned. Width is optional, but if included specifies that only occurences on a width byte boundary will be found.
Return value | Numeric - position of expC2 in expC1 if found, 0 otherwise.
Example | /* Use AT() to find the position of a state in * a string of state abbreviations. * e.g., #S"Stateabbr" == "GA" */ long pos; pos=AT(#S"Stateabbr", "AKALGANYTX"); /* Returns 5 - GA found at position 5*/ pos=AT(#S"Stateabbr", "AKALGANYTX",2); /* Returns 3 - GA found in 3rd multiple of 2 */ pos=AT(#S"Stateabbr", "AKALGANYTX",3); /* Returns 0 - GA not found on a multiple of 3 */


Detailed Descriptions

BINLOOKUP

Use BINLOOKUP to retrieve a binary value by cell address or row and column position from a table of type binary (.BIN).
Syntax | BINLOOKUP(table_name, element) - or - BINLOOKUP(table_name, row, col)
Description | This function retrieves a specified binary value from a table either by element or row and column position. If element is specified, the table is treated as a one-dimensional array, starting at element 1. If row and col are specified, the table is treated as a two-dimensional array starting at 1,1 (depends on # columns per row specified at table import). Row and col are resolved to element internally.
Return value | Numeric - the binary value requested or 0 if not found.
See Also | LOOKUP, ILOOKUP, RLOOKUP
Example | long lval, rcval; lval = BINLOOKUP("MYBINTBL.BIN",32); rcval = BINLOOKUP("MYBINTBL.BIN",4,3);


Detailed Descriptions

DATE_DAY_IOP

Returns day portion of date.

Syntax

int DATE_DAY_IOP(test_date)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether the test_date is an empty string. If it is, the function returns DT_EMPTY.

The function then determines whether test_date is valid (see VALID_DATE_IOP). If the date is not valid, this function returns DT_ERROR.

The function then checks to see if the day portion of the input date is blank. If it is, the function returns DT_DAY_EMPTY.

The day is extracted from the last two digits of the input test_date.

Return value

If the input date is valid, this function returns the day portion of the date as a numeric value.

If the input date is an empty string, this function returns DT_EMPTY.

If the input date is not valid, this function returns DT_ERROR.

If the day portion of the input date is blank, this function returns DT_DAY_EMPTY.

Example

int birth_month, birth_day;

birth_day = DATE_DAY_IOP(#S"Date of Birth");

/* ALWAYS check date IOP functions for error codes! */

if (birth_day == DT_ERROR)

{

error_text("Date of Birth not valid: %DC");

return FAIL;

}

else if (birth_day == DT_EMPTY)

{

error_text("Date of Birth is empty string");

return FAIL;

}

else if (birth_day == DT_DAY_EMPTY)

{

error_text("Day portion of Date of Birth is empty");

return FAIL;

}

birth_month = DATE_MONTH_IOP(#S"Date of Birth");

/* No need to check error codes again... we already

* know the birth date is complete and valid.

*

* Compare to today's month and day.

*/

if (birth_month == DATE_MONTH_IOP(DT_TODAY) &&

birth_day == DATE_DAY_IOP(DT_TODAY))

{

error_text("Happy birthday!");

return FAIL;

}

return PASS;


Detailed Descriptions

DATE_MONTH_IOP

Returns month portion of date.

Syntax

int DATE_MONTH_IOP(test_date)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether the test_date is an empty string. If it is, the function returns DT_EMPTY.

The function then determines that test_date is valid (see VALID_DATE_IOP). If the date is not valid, this function returns DT_ERROR.

The function then checks to see if the month portion of the input date is blank. If it is, the function returns DT_MONTH_EMPTY.

The month is extracted from the fifth and sixth digits of the input test_date.

Return value

If the input date is valid, this function returns the month portion of the date as a numeric value.

If the input date is an empty string, this function returns DT_EMPTY.

If the input date is not valid, this function returns DT_ERROR.

If the month portion of the input date is blank, this function returns DT_MONTH_EMPTY.

Example

/* This edit ensures that the month+year of Date of Diagnosis

* does not precede the Date of Birth.

*/

int birth_year, birth_month;

int dx_year, dx_month;

birth_month = DATE_MONTH_IOP(#S"Date of Birth");

/* ALWAYS check date IOP functions for error codes! */

if (birth_month == DT_ERROR)

{

error_text("Date of Birth not valid: %DC");

return FAIL;

}

else if (birth_month == DT_EMPTY)

{

error_text("Date of Birth is empty string");

return FAIL;

}

else if (birth_month == DT_MONTH_EMPTY)

{

error_text("Month portion of Date of Birth is empty");

return FAIL;

}

/* Get the year portion. No need to check error codes;

* we already know the date is complete and valid.

*/

birth_year = DATE_YEAR_IOP(#S"Date of Birth");

/* Perform the same set of tests on the Date of Diagnosis */

dx_month = DATE_MONTH_IOP(#S"Date of Diagnosis");

if (dx_month == DT_ERROR)

{

error_text("Date of Diagnosis not valid: %DC");

return FAIL;

}

else if (dx_month == DT_EMPTY)

{

error_text("Date of Diagnosis is empty string");

return FAIL;

}

else if (dx_month == DT_MONTH_EMPTY)

{

error_text("Month portion of Date of Diagnosis is empty");

return FAIL;

}

dx_year = DATE_YEAR_IOP(#S"Date of Diagnosis");

/* Evaluate the results */

if (birth_year < dx_year)

return PASS;

else if (birth_year == dx_year)

{

if (birth_month <= dx_month)

return PASS;

}

return FAIL;


Detailed Descriptions

DATE_YEAR_IOP

Returns year portion of date.

Syntax

int DATE_YEAR_IOP(test_date)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether the test_date is an empty string. If it is, the function returns DT_EMPTY.

The function then determines that test_date is valid (see VALID_DATE_IOP). If the date is not valid, this function returns DT_ERROR.

The year is extracted from the first four digits of the input test_date.

Return value

If the input date is valid, this function returns the year portion of the date as a numeric value.

If the input date is an empty string, this function returns DT_EMPTY.

If the input date is not valid, this function returns DT_ERROR.

Example

/* This edit will compare Date of Conclusive DX to

* Date of Last Contact to identify cases where patient

* survived for at least 5 years.

*/

int yy_cdx, yy_last;

yy_cdx = DATE_YEAR_IOP(#S"Date of Conclusive DX");

yy_last = DATE_YEAR_IOP(#S"Date of Last Contact");

/* Check for basic validity */

if (yy_cdx == DT_ERROR || yy_cdx == DT_EMPTY)

{

error_text("Date of Conclusive DX error: %DC");

return FAIL;

}

if (yy_last == DT_ERROR || yy_last == DT_EMPTY)

{

error_text("Date of Last Contact error: %DC");

return FAIL;

}

if ((yy_last - yy_cdx) >= 5)

return PASS;

else

{

error_text("May not have survived at least 5 years from DX.");

return WARN;

}


Detailed Descriptions

DATECMP_IOP

Compares two dates by subtracting date2 from date1.

Syntax

int DATECMP_IOP(date1, date2, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

Compares two dates by subtracting date2 from date1. Date constants should be specified as quoted strings in "CCYYMMDD" format. For example, January 31, 2010, would be written as "20100131".

The third parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

Return value

If the input dates are valid, the function returns a numeric value:

1 if date1 > date 2

0 if date1 == date2

-1 if date1 < date2

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and/or day portion of either date is blank and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

int dtcmp;

dtcmp = DATECMP_IOP(#S"Date of Diagnosis",

#S"Date Case Completed", DT_EXACT);

/* ALWAYS check date IOP functions for error codes! */

if (dtcmp == DT_ERROR)

{

/* Find out WHICH date is in error */

if (!VALID_DATE_IOP(dateDx))

error_text("Date of Diagnosis is invalid: %DC");

else if (!VALID_DATE_IOP(dateComplete))

error_text("Date Case Completed is invalid: %DC");

return FAIL;

}

else if (dtcmp == DT_EMPTY)

{

error_text("At least one of the dates is an empty string");

return FAIL;

}

/* Because we are using DT_EXACT, we have to check for

* DT_UNKNOWN.

*

* This would not be necessary if the min_max_flag were

* DT_MIN or DT_MAX

*/

else if (dtcmp == DT_UNKNOWN)

{

error_text("Cannot return exact results from incomplete dates");

return FAIL;

}

if (dtcmp == 0)

save_text("Dates are the same");

else if (dtcmp > 0)

save_text("Date 1 > Date 2");

else if (dtcmp < 0)

save_text("Date 1 < Date 2");

return FAIL;


Detailed Descriptions

DAYDIFF_IOP

Find the difference between two dates, counted in days.

Syntax

int DAYDIFF_IOP(begDt, endDt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

Calculates the difference between two dates, counted in days. The third parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

The difference in dates may be negative if begDt is after endDt.

Note: The DAYDIFF_IOP function and its counterpart, DAYINTERVAL_IOP, may return unexpected results when portions of the dates being evaluated are missing. It is especially important to check for all possible error codes in the return value and take appropriate steps.

Above all, test your EDIT! Try every combination of complete and partial dates you can imagine. The example shown here may help you design your implementation.

Return value

If the input dates are valid, this function returns the number of days between the dates.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and/or day portion of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

/* This edit will compare Date of Diagnosis to

* Date of Conclusive DX to ensure that the conclusive

* diagnosis occurred at least 61 days after diagnosis.

*/

int mm_cdx, yy_cdx, mm_dx, yy_dx;

int days_diff;

/* We'll need to consider each part of the dates.

* Begin with the year portion.

*/

yy_cdx = DATE_YEAR_IOP(#S"Date of Conclusive DX");

yy_dx = DATE_YEAR_IOP(#S"Date of Diagnosis");

/* Check for basic validity */

if (yy_cdx == DT_ERROR || yy_cdx == DT_EMPTY)

{

error_text("Date of Conclusive DX error: %DC");

return FAIL;

}

if (yy_dx == DT_ERROR || yy_dx == DT_EMPTY)

{

error_text("Date of Diagnosis error: %DC");

return FAIL;

}

/* Now get the month parts of the dates */

mm_cdx = DATE_MONTH_IOP(#S"Date of Conclusive DX");

mm_dx = DATE_MONTH_IOP(#S"Date of Diagnosis");

/* Do we have any missing month parts? */

if (mm_dx == DT_MONTH_EMPTY)

{

/* If Date of Conclusive Dx month is greater than 02, year of

* conclusive dx must be greater than year of dx

*/

if (mm_cdx > 2)

{

if (yy_cdx > yy_dx)

return PASS;

else

{

error_text("DX month unknown, year <= Conclusive year");

return FAIL;

}

}

else

{

error_text("Date of Diagnosis month unknown");

return FAIL;

}

}

if (mm_cdx == DT_MONTH_EMPTY)

{

/* If Date of Dx is less than 11, then year of conclusive dx

* must be greater than date of dx

*/

if (mm_dx < 11)

{

if (yy_cdx > yy_dx)

return PASS;

else

{

error_text("Conclusive month unknown, year <= DX year");

return FAIL;

}

}

else

{

error_text("Date of Conclusive DX month unknown.");

return FAIL;

}

}

/* Evaluate two dates that may or may not have the day portion.

* Allow the maximum window for comparison.

*/

days_diff = DAYDIFF_IOP(#S"Date of Diagnosis",

#S"Date of Conclusive DX", DT_MAX);

if (days_diff > 60)

return PASS;

else

return FAIL;


Detailed Descriptions

DAYINTERVAL_IOP

Checks to see if two dates fall within an interval, counted in days, of each other.

Syntax

int DAYINTERVAL(begDt, endDt, minInt, maxInt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

DAYINTERVAL_IOP calculates the number of days between begDt and endDt. If that calculated value is greater than or equal to minInt and less than or equal to maxInt, the function returns TRUE. If it falls outside that range, the function returns FALSE.

The fifth parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

Return value

If the input dates are valid:

TRUE | if begDt and endDt are within the interval.
FALSE | if the interval between the dates exceeds the difference between minInt and maxInt.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and/or day portion of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

int is_within_interval;

is_within_interval = DAYINTERVAL_IOP(#S"Date of Diagnosis",

#S"Date Conclusive DX", 0, 60, DT_EXACT);

/* ALWAYS check date IOP functions for error codes! */

if (is_within_interval == DT_ERROR)

{

/* Find out which date is invalid */

if (!VALID_DATE_IOP(#S"Date of Diagnosis"))

error_text("Date of Diagnosis error: %DC");

else

{

if (!VALID_DATE_IOP(#S"Date Conclusive DX"))

error_text("Date Conclusive DX error: %DC");

}

return FAIL;

}

else if (is_within_interval == DT_EMPTY)

{

error_text("At least one of the dates is an empty string");

return FAIL;

}

/* Because we are using DT_EXACT, we must check for

* dates that are missing month or day portions.

*/

else if (is_within_interval == DT_UNKNOWN)

{

error_text("At least one of the dates is missing month or day");

return FAIL;

}

if (is_within_interval)

error_text("Date Conclusive Dx within 60 days of Date Dx");

else

error_text("Date Conclusive Dx outside 60 day window");

return FAIL;


Detailed Descriptions

EMPTY

Determines if a field or variable is blank.
Syntax | EMPTY(string | field)
Description | Determines if string or field is blank, meaning composed entirely of 0 or more spaces.
Return value | TRUE if string is blank, FALSE otherwise.
Example | /* In this example, a field is not allowed to be blank. */ IF (EMPTY(#S"State")) { RETURN FAIL; } RETURN PASS;


Detailed Descriptions

ERROR_MSG

Changes edit error message number.
Syntax | ERROR_MSG( number )
Description | ERROR_MSG changes the error message number of an edit, allowing an edit to return a context-specific error message. ERROR_MSG always returns FAIL so it may be used with a RETURN statement to FAIL an edit.
Return value | Numeric, FAIL.
See Also | RETURN, ERROR_TEXT
Example | /* In this example, the error message number is changed to 6. * A FAIL value is returned from the edit. */ return ERROR_MSG(6); /* ERROR_MSG can be used to change the default * message for a warning, as well. */ ERROR_MSG(6); return WARN;


Detailed Descriptions

ERROR_TEXT

Changes edit error message text.

Syntax

ERROR_TEXT( string )

Description

ERROR_TEXT changes the error message to a literal string, allowing an edit to return a context-specific error message. ERROR_TEXT always returns FAIL and can be used with a RETURN statement.

Notes:

  • Unlike SAVE_TEXT, the contents of a call to ERROR_TEXT will not display until the edit RETURNs. Thus, the message may change throughout the run of the edit, and only its final value will be displayed.

  • Unlike ERROR_MSG, the message can be created on-the-fly; that is, the message does not have to be predefined in the Error Messages list to be used in an edit.

Return value

Numeric, FAIL.

See Also

ERROR_MSG, RETURN, SAVE_TEXT

Example

/* The error message is changed to "Invalid value."

* A FAIL value is returned from the edit.

*/

RETURN ERROR_TEXT("Invalid Value");

/* Keep changing the ERROR_TEXT value throughout the edit,

* to cover multiple error conditions.

*/

int months_diff

months_diff =

(MONTHDIFF_IOP(#S"Date of DX", #S"Date of Birth", DT_MIN));

/* Set the message to a default value */

ERROR_TEXT("Date of Dx is later than Date of Birth");

if (months_diff <= 7)

{

if ( !INLIST(#S"Over-ride Age/Site/Morph", "2,3" ))

{

/* This changes the message that will be displayed.

* Over-ride must be set if case diagnosed in utero */

ERROR_TEXT("Set over-ride to 2 or 3");

}

}

else

{

/* This changes the message that will be displayed.

* Date of Birth cannot be more than 7 months after DX */

ERROR_TEXT("Birth is more than 7 months after DX");

}

/* The message that displays will be the one from the last call

* to ERROR_TEXT. */

return FAIL;


Detailed Descriptions

EXTERNALDLL

Allows calls to functions in external Dynamic Link Libraries (DLLs) from within EDITS.

Syntax

int ExternalDLL(dll_name, func_name [, parm1 [, parm2 [, ...parm10])

Description

In order to make EDITS processing more robust, data in external sources can be accessed by function calls from Edit Logic. Such external calls may include, for example, calling functions in the Collaborative Stage Dynamic Link Library (CStage.dll).

Assumptions:

  • The external sources must be Dynamic Link Libraries (*.DLL) for Windows, or Shared Objects (*.so) for Linux.

  • The function call from Edit Logic identifies the name of the DLL and the name of the function to be accessed in the DLL.

  • The mechanism for accessing the external functions is flexible regarding the number of parameters to the DLL function, and the data type of those parameters.

  • The Edit Engine has no knowledge of the called DLL or its functions; it serves merely as a conduit between the Edit Logic and the external DLL.

  • Called DLLs must be modified to be Edit Engine-aware. (Refer to EDITS API documentation for client application programmers, topic EDITS and External DLLs, for details.)

Parameters:

  • dll_name and func_name must be provided. The dll_name should be the file name, with or without the extension. That is, either "CStage.dll" or simply "CStage" will work.

Note to Linux users: The Engine will replace extension ".dll" with ".so" for you. You do NOT have to modify your edits to use the Shared Objects extension. That is, if the edit uses "CStage.dll", under the Linux environment the Engine will change that to "CStage.so".

  • parm1 through parm10 are optional parameters; that is, the Edit Engine does not require that you provide them, but the called DLL will have its own requirements. See examples.

Return value

Integer. The meaning of the value depends upon the documentation from the called DLL.

Note that this mechanism supports passing variables by reference, so that a function call can modify one or more parameters as well as return a value.

Example

int t_schema_count,

t_schema_number,

t_table_number,

t_code_is_valid;

char t_site[5], /* Primary Site */

t_hist[5], /* Histologic Type ICD-O-3 */

t_discrim[4], /* CS Site-Specific Factor25 */

t_code[4];

strcpy(t_site, #S"Primary Site");

strcpy(t_hist, #S"Histologic Type ICD-O-3");

strcpy(t_discrim, #S"CS Site-Specific Factor25");

/* This function takes no optional parm1..parm10 parameters,

* and returns the count.

*/

t_schema_count =

ExternalDLL("CStage.dll","CStage_get_number_of_schemas");

/* This call uses optional parm1..parm3 */

t_schema_number =

ExternalDLL("CStage.dll","CStage_get_schema_number",

t_site, t_hist, t_discrim);

if (t_schema_number < 0 || t_schema_number > t_schema_count)

{

/* error */

return FAIL;

}

/* t_table_number is a hard-coded value looked up

* by the EDIT author

*/

t_table_number = 1;

strcpy(t_code, "888");

/* This call uses optional parm1..parm4 */

t_code_is_valid =

ExternalDLL("CStage.dll", "CStage_code_is_valid",

t_schema_number, t_table_number, 0, t_code);

if (t_code_is_valid == 0)

return FAIL;

else

return PASS;


Detailed Descriptions

FMTSTR

Creates a formatted ASCII string representation of a number.

Syntax

FMTSTR(var_name, format_str, number)

Description

Var_name is a character array such as "char name[20]".

The format specifier for how the data will be formatted is format_str.The number section will always start with a "%", and end with an "ld". A width between the "%" and "ld" may be included. When width is used, a "-" after the "%" will make the number left justified, and leading the width with a "0" will make it zero-filled. Format_str can contain any text as well as the format specifier.

Number can be any numeric constant, variable, or expression.

Return value

Pointer to var_name

Example

char mystr[10];

long mynum;

mynum=25;

fmtstr(mystr,"%05ld",mynum);

print(mystr); /* Prints "00025" */

More Format Examples:
Format | Value | Output
”%ld" | 5 | "5"
"%5ld" | 25 | " 25"
"%-5ld" | 10 | "10 "
”AB%05ldCD” | 25 | ”AB00025CD”
"%05ld" | 2 | "00002"


Detailed Descriptions

GETFIELD

Retrieves data from a field.
Syntax | char *GETFIELD(field [, record_layout_number ])
Description | GETFIELD retrieves data from a field in an active record layout (the default would be an edit record layout, or an alternate record layout if specified. This function, in combination with other EDITS functions, allows programmatic recoding of fields.
Return value | Contents of field in string format.
See Also | PUTFIELD
Example | /* divide age by 5 to get an age group */ char dest[20]; int i; i=val(GETFIELD(#S”Age”)) /5; fmtstr(dest,”%02",i); PUTFIELD(#S”Age Group”, dest);


Detailed Descriptions

GETVAR

Returns value of a common variable or size of array.

Syntax

GETVAR(var_name [, element])

Description

This EDITS language function returns a pointer to a copy of the common variable specified by name 'var_name' and optional array element 'element'.

Common variables are variables that are shared between the calling program and the EDITS language. The API can get and set common variables via calls to EEx_GetVar, EEx_GetVarIndex, EEx_SetVar, and EEx_SetVarIndex. These variables can be accessed within the EDITS language by calls to GETVAR and SETVAR.

To get the size of an array, call GETVAR with an element of 0. The size returned is the highest defined element of the array. Common variable arrays are indexed starting from 1.

To clear a common variable or common variable array, call SETVAR with the name of the variable or array and an empty argument (""). (When clearing all elements of an array, do not supply a subscript.)

A call to GETVAR or EEx_GETVAR with a undefined name passed will return a pointer to a null string.

Return value

Character or Numeric.

See Also

SETVAR

Example

IF(strcmp(GETVAR("Status"),"DONE")==0)

RETURN PASS;

RETURN FAIL;


Detailed Descriptions

ILOOKUP

Searches a table index for the presence of a specified search value.

Syntax

int ILOOKUP(string | field, TableName[.DBF[.tag]]);

Description

ILOOKUP performs an indexed lookup for a key only; the actual database record is not retrieved, unlike LOOKUP. The performance of ILOOKUP is faster than LOOKUP.

Refer to LOOKUP Functions and User Tables for a discussion about the differences among functions LOOKUP, RLOOKUP and ILOOKUP.

Return value

TRUE if found, FALSE if not found

See Also

LOOKUP, RLOOKUP, BINLOOKUP

Example

/* Concatenate State and Zip Code to search for valid combination.

* #S"State" is "GA", #S"Zip Code" is "30341" */

char searchstr[8];

strcpy(searchstr,#S"State"); /* searchstr contains "GA" */

strcat(searchstr,#S"Zip Code");

/* searchstr now contains "GA30341" */

if(ILOOKUP(searchstr, "ZIPCODE.DBF.STATEZIP"))

return PASS;

...

/* STATEZIP is an index of valid state and zip code concatenations */


Detailed Descriptions

INLIST

Is value contained in a list?

Syntax

int INLIST(string|field, list of values or ranges

[,match_pattern [,start_pos [,length ] ] ] )

Description

Looks for a value in a list or range of values. Values in the list should be separated by commas, and numeric ranges can be specified by a hyphen (-). Match_pattern, start_pos, and length are optional parameters; however, if length is specified, the match_pattern and start_pos must have been supplied.

Match_pattern options are documented in the MATCH function. Start_pos and length allow a substring to be checked for range or value only; the match pattern must cover the entire field or string.

Return value

Returns TRUE if the string is contained in the list of values.

Example

if (INLIST(#S"DxZIP", "30319, 20374, 19990-19999"))

...

/* To edit a four character field that can range from

* "C100-C150" or "C225-C229," write the inlist function as: */

if(INLIST(#S"C_FIELD","100-150,225-229","Cddd",2,3))

return PASS;

/* The match pattern is interpreted as a 'C' followed by three

* digits; the range of values is checked starting at the second

* character of the string, for three characters.

 */


Detailed Descriptions

JUSTIFIED

Is a string justified?
Syntax | int JUSTIFIED(string|field, LEFT | RIGHT)
Description | JUSTIFIED tests a field or string for left or right justification. A string or field is considered left justified if there is a non-blank in the first character. A string or field is considered right justified if the last character is non-blank. For fields, the local length as defined in the record layout determines what position is last character.
Return value | TRUE if justified, FALSE if not.
Example | if (JUSTIFIED(#S"LastName",LEFT)) ...


Detailed Descriptions

LEFT

Returns the leftmost characters of a string.

Syntax

char *LEFT(string|field, num_chars)

Description

Returns a pointer to the leftmost num_chars of the string. If the string is shorter than num_chars, the entire string is returned.

Note that to receive the returned value, you must use one of the string handling functions: STRCPY, STRCAT or SUBSTR.

Return value

Character.

Example

/* #S"Phone Number" contains "(770) 488-4227" */

char dest[10];

strcpy(dest, LEFT(#S"Phone Number",6));

/* dest now contains "(770) " */


Detailed Descriptions

LOOKUP

Looks for a string or field in a DBF table

Syntax

int LOOKUP(string | field, TableName[.DBF[.tag]]);

Description

Looks for a string or field in a DBF table. Indexed lookups can be performed on indexed tables by specifying the index tag name after the table name. The use of indexed lookups is preferred for performance advantages.

Unindexed (i.e., serial) lookups will search until a record matches the search criteria or end of file, whichever occurs first.

When performing an indexed lookup, if your edit needs only to determine whether a value exists in a table (rather than needing to retrieve values from the record that is found), you should consider using ILOOKUP for its incremental performance advantages. Refer to LOOKUP Functions and User Tables for a discussion about the differences among functions LOOKUP, RLOOKUP and ILOOKUP.

Return value

TRUE if found, FALSE if not found

See Also

ILOOKUP, RLOOKUP, BINLOOKUP

Example

/* Concatenate State and Zip Code to search for valid combination.

* #S"State" is "GA", #S"Zip Code" is "30341" */

char searchstr[8];

strcpy(searchstr,#S"State");

/* searchstr contains "GA" */

strcat(searchstr,#S"Zip Code");

/* searchstr contains "GA30341" */

if(LOOKUP(searchstr,"ZIPCODE.DBF.STATEZIP"))

return PASS;

...

/* STATEZIP is an index of valid state and zip codes concatenations */


Detailed Descriptions

LOWER

Converts string to lower case.
Syntax | char *LOWER(string|field)
Description | LOWER returns a copy of a string with all upper case characters converted to lower case. The original is left unchanged.
Return value | Returns a copy of lower case string. Note that to receive the return value, it must be wrapped in one of the string handling functions: STRCPY, STRCAT or SUBSTR.
See Also | UPPER
Example | char string1[30], string2[20]; strcpy(str1, "Hello"); strcpy(str2, LOWER(str1)); /* str2 gets "hello" */


Detailed Descriptions

MATCH

Tests string for a match against a pattern.

Syntax

int MATCH(string, pattern);

Description

MATCH provides a pattern matching language for validating any string, including repeated patterns and wildcards.

The match routine allows True/False validations of any string against a regular expression pattern, or in the simplest case, a list of possible options. Its input is a null-terminated pattern and string. Wildcards, masks, repetition, ranges of values and ranges of instances are supported.

Mask Characters and Wildcards

Symbol | Meaning
x | Specifies any alphanumeric character
@ | Specifies any character except blank
? | Specifies any character
a | Specifies any alphabetic character
u | Specifies any uppercase alphabetic character
l | Specifies any lowercase alphabetic character
b | Specifies a blank
d | Specifies a digit 0 - 9
! | Specifies that following character is to be treated as a literal rather than a mask.
: | Specifies a range for a character position, used as 1:5 would allow only values from 1 to 5. The range operator applies only to a single character position.
{ } | Encloses a sub-pattern. Can be followed by repetition characters and control strings. Without repetition or control strings, pattern within braces must be met once only.
[ ] | Encloses an optional sub-pattern, meaning the match is valid with or without the enclosed pattern.

Repetition Characters

Symbol | Meaning
+ | Character, mask, or braced pattern must occur at least once, may be repeated infinitum.
* | Character, mask, or braced pattern is optional and can be repeated.

Notes on Match

MATCH strips trailing blanks off its target strings before performing the match. Because of this, do not use "b" at the end of a pattern to check for blanks at the end of a string. (As a special case, a pattern consisting of only "b" will pass an empty string.)

Braces and brackets - can be nested.

When matching patterns where one is a subset of a larger one, test larger first: Example is a Zip-Code that can be five or nine digits. If coded as

match("203741234","[ddddd,ddddddddd]")

it will fail, as it fulfilled a match on the first five digits, but had characters remaining that went unmatched. Code it as

match("203741234","[ddddddddd,ddddd]")

and

match("20374","[ddddddddd,ddddd]")

so that both five and nine digit Zip-Codes will pass.

Sample Match Patterns

Check for 001-009 followed by a decimal and digit

MATCH(#S"Cause of Death","001:9.d");

Check for blank or 1

MATCH(string,"[1]")

Check for 9 or 5 digits

MATCH(string,"ddddddddd,ddddd")

Check for codes of C341-C349, C384, C500-C509, C569, C570

MATCH(#S"Site","C341:9,C384,C50d,C569,C570")

or

MATCH(#S"Site","C{341:9,384,50d,569,570}")

Check for 2 digits or 2 uppercase letters

MATCH(#S"SequenceNumber","dd,uu")

Accession Number must start with 7, 8 or 9

MATCH(#S"AccNum","{7,8,9}ddddd") or

MATCH(#S"AccNum","7:9ddddd")

Accept Zip Codes like 30341-3724, 30341, or 303413724

MATCH(#S"Zip","ddddd[[!-]dddd]")

Area code must be 404

MATCH(#S"Phone","404 ddd!-dddd")

City or State Names (letters possibly with spaces)

MATCH(#S"City","a{a,b}*")

Time - 12-hour clock, optional :, optional AM or PM

MATCH(#S"Time","{01:9,10:2}[!:]0:5d[b*[!am,pm]]")

Time - 24-hour clock

MATCH(#S"Time","{0:1d,20:3}[!:]0:5d")

Return value

Logical (TRUE or FALSE)

See Also

INLIST

Example

Test variable YEAR for years 70-85

if( match(YEAR,"70:9,80:5") ) ...


Detailed Descriptions

MONTHDIFF_IOP

Find the difference between two dates, counted in months.

Syntax

int MONTHDIFF_IOP(begDt, endDt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

Calculates the difference between two dates, counted in months. A month is calculated by counting the number of days between begDt and endDt, and dividing the result by 30. Note that the function rounds down; a difference of 89 days will calculate to 2 months; 90 days calculates to 3 months.

The third parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

The difference in dates may be negative if begDt is after endDt.

Return value

If the input dates are valid, this function returns the number of months between the dates.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and/or day portion of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

/* This edit will compare Date of Diagnosis to

* Date of Conclusive DX to ensure that the conclusive diagnosis

* occurred at least 2 months after diagnosis.

*/

int mm_cdx, yy_cdx, mm_dx, yy_dx;

int months_diff;

yy_cdx = DATE_YEAR_IOP(#S"Date of Conclusive DX");

yy_dx = DATE_YEAR_IOP(#S"Date of Diagnosis");

/* Check for basic validity */

if (yy_cdx == DT_ERROR || yy_cdx == DT_EMPTY)

{

error_text("Date of Conclusive DX error: %DC");

return FAIL;

}

if (yy_dx == DT_ERROR || yy_dx == DT_EMPTY)

{

error_text("Date of Diagnosis error: %DC");

return FAIL;

}

mm_cdx = DATE_MONTH_IOP(#S"Date of Conclusive DX");

mm_dx = DATE_MONTH_IOP(#S"Date of Diagnosis");

/* We already know the dates are valid from the calls to

* DATE_YEAR_IOP. But if both dates consist of only the year

* portion, and the years are equal, we might want to issue a

* warning.

*/

if (mm_cdx == DT_MONTH_EMPTY &&

mm_dx == DT_MONTH_EMPTY)

{

if (yy_cdx == yy_dx)

{

error_text("Dates w/YEAR only; cannot say definitively.");

return WARN;

}

}

/* Evaluate two dates that may or may not have the month and day

* portions. Allow the maximum window for comparison.

*/

months_diff = MONTHDIFF_IOP(#S"Date of Diagnosis",

#S"Date of Conclusive DX", DT_MAX);

if (months_diff > 2)

return PASS;

else

return FAIL;


Detailed Descriptions

MONTHINTERVAL_IOP

Checks to see if two dates fall withn an interval, counted in months, of each other.

Syntax

int MONTHINTERVAL(begDt, endDt, minInt, maxInt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

MONTHINTERVAL_IOP calculates the number of months between begDt and endDt. (A month is calculated by counting the number of days between begDt and endDt, and dividing the result by 30. Note that the function rounds down; a difference of 89 days will calculate to 2 months; 90 days calculates to 3 months.) If that calculated value is greater than or equal to minInt and less than or equal to maxInt, the function returns TRUE. If it falls outside that range, the function returns FALSE.

The fifth parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

Return value

If the input dates are valid:

TRUE | if begDt and endDt are within the interval.
FALSE | if the interval between the dates exceeds the difference between minInt and maxInt.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and day portions of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

int is_within_interval;

is_within_interval = MONTHINTERVAL_IOP(#S"Date of Diagnosis",

#S"Date Conclusive DX", 0, 2, DT_EXACT);

/* ALWAYS check date _IOP functions for error code! */

if (is_within_interval == DT_ERROR)

{

/* Find out which date is invalid */

if (!VALID_DATE_IOP(#S"Date of Diagnosis"))

error_text("Date of Diagnosis error: %DC");

else

{

if (!VALID_DATE_IOP(#S"Date Conclusive DX"))

error_text("Date Conclusive DX error: %DC");

}

}

else if (is_within_interval == DT_EMPTY)

{

error_text("At least one of the input dates is an empty string");

}

/* Because we used DT_EXACT, we must check for DT_UNKNOWN.

*/

else if (is_within_interval == DT_UNKNOWN)

{

error_text("Cannot give exact results with partial input date(s)");

}

else

{

if (is_within_interval)

error_text("Date Conclusive Dx within 2 months of Date Dx");

else

error_text("Date Conclusive Dx outside 2 month window");

}

return FAIL;


Detailed Descriptions

NAMEEXPR

Returns the value of a variable by name.
Syntax | char *NAMEEXPR(string)
Description | NAMEEXPR provides indirect access to variables by their name. Its primary use is to allow construction of variable names.
Return value | Value of variable
Example | A DBF table has fields VAL01-VAL50. It may be easier to write code to index through all the fields, as would be possible with an array. char varname[20]; int i; for(i=1;i<=50;i=i+1) { fmtstr(varname,"VAL%02ld",i); /* format name of string */ if(strcmp(NAMEEXPR(varname), "25")==0) Return PASS; }


Detailed Descriptions

PUTFIELD

Writes a new value into a field
Syntax | int PUTFIELD(field, string|field [, record_layout_number ])
Description | PUTFIELD writes a new value into field and sets the RECDIRTY flag for that record layout. This function, in combination with other EDITS functions, allows programmatic recoding of fields. If record_layout_number is included, the field in that record layout is updated. This would be necessary when the field is defined more than one time, once in a regular edit record layout and again in an alternate record layout. Record_layout_number must be specified to update a field in an alternate record layout. It is the calling application’s responsibility to save a record layout when necessary.
Return value | 1 if successful, 0 otherwise.
See Also | GETFIELD, EDITS API calls EEx_RecWrite, EEx_RecWriteClear
Example | /* divide age by 5 to get an age group */ char dest[20]; int i; i=val(GETFIELD(#S”Age”)) /5; fmtstr(dest,”%02",i); PUTFIELD(#S”Age Group”, dest);


Detailed Descriptions

RIGHT

Returns the rightmost characters of a string.
Syntax | char *RIGHT(string|field, num_chars)
Description | Returns a pointer to rightmost num_chars (trailing blanks removed!) If the string is shorter than num_chars, the entire string is returned.
Return value | Pointer to the rightmost num_chars of string.
Example | char dest[5]; strcpy(dest, RIGHT(#S”Zip Code”,4)); /* dest gets last 4 digits of 9-digit zip */


Detailed Descriptions

RLOOKUP

Searches an indexed DBF table for highest key that is less than or equal to the search key.

Syntax

int RLOOKUP(Item, Filename);

Description

RLOOKUP will search an indexed DBF table for the highest record with its key value less than or equal to the search key. In the case of a search key higher than any key in the file, the highest key will be returned. Only if the search criteria is lower than the lowest key in the table will RLOOKUP fail, and an empty record will be returned.

This type of search is sometimes called a "soft seek", and is extremely useful for looking for values that fall within a range. (The "R" in RLOOKUP stands for "Range".)

IMPORTANT: Because this function will always give you its closest matching record, it is up to the calling edit to check table columns returned by RLOOKUP to see if the record returned actually contains the intended range if other columns further limit the range of acceptable values. See the example and discussion, below.

Refer to LOOKUP Functions and User Tables for a discussion about the differences among functions LOOKUP, RLOOKUP and ILOOKUP.

Return value

TRUE if found, FALSE if not found

See Also

LOOKUP, ILOOKUP, BINLOOKUP

Example

/* This edit checks Primary Site and Histologic Type

* combinations for impossible combinations by checking a

* table of impossible combinations.

*/

/* Declare variables in table to be referenced in edit */

tablevar site, histlo, histhi;

/* Declare concatenated Site/Histology variable */

char SiteHist[9];

/* Concatenate Site, Histology */

strcpy(SiteHist,#S"Primary Site");

strcat(SiteHist,#S"Histologic Type");

/* look up closest record >= impossible search key */

if(RLOOKUP(SiteHist,"IF38IMPO.DBF.SITEHISTLO"))

{

/* If found, confirm it is the impossible case */

if(strcmp(#S"PrimarySite",SITE)==0 and

strcmp(#S"HistologicType",HISTLO)>=0 and

strcmp(#S"HistologicType",HISTHI)<=0)

{

return FAIL;

}

}

TABLE INFORMATION FOR THIS EXAMPLE

IF38IMPO.DBF is the table of impossible primary site/histology combinations. This table was originally extracted from the SEER COBOL code.

Structure

FIELD NAME | TYPE | WIDTH
SITE | Character | 4
HISTLO | Character | 4
HISTHI | Character | 4

Indexes

SITEHISTLO

Index on SITE+HISTLO Tag SITEHISTLO

Sample Data

RECORD # | SITE | HISTLO | HISTHI
1 | C000 | 8090 | 8096
2 | C001 | 8090 | 8096
3 | C002 | 8090 | 8096
... |  |  |
98 | C410 | 8010 | 8060
99 | C410 | 8075 | 8671
100 | C410 | 8720 | 8790

Sample Input and Outcome

SITE | HIST | FOUND IN TABLE | IMPOSSIBLE VALUE
C000 | 8089 | Not found | No
C000 | 8096 | C000 8090 9096 | Yes
C000 | 8097 | C000 8090 9096 | No
C410 | 8719 | C410 8075 8671 | No
C410 | 8777 | C410 8720 8790 | Yes
C999 | 9999 | C410 8720 8790 | No


Detailed Descriptions

SAVE_ERROR_TEXT

Generates error messages but does not set flags.

Syntax

int SAVE_ERROR_TEXT(msg1 [, msg2 [...msgn]])

Description

Generates error messages but does not set flags. This function causes FAIL to be returned from the edit. It can be used to return multiple error messages from the same edit, unlike ERROR_MSG, which changes the default error message only. Errors reported by SAVE_ERROR_TEXT are in addition to any reported by ERROR_MSG or other returns from the edit.

This function is poorly named, in that it does not accept a text string for a parameter the way SAVE_TEXT and ERROR_TEXT do. Its behavior is analogous to that of SET_WARNING, which likewise accepts multiple numeric parameters; the difference between SAVE_ERROR_TEXT and SET_WARNING is that the former causes a FAIL to be returned, and the latter causes a WARN to be returned.

Return value

None

See Also

SET_WARNING, SAVE_TEXT, ERROR_MSG

Example

/* If Vital Status is empty, two error messages will be

* displayed: 293 says "Vital Status not valid".

* This condition will also cause the edit to return

* FAIL, which will trigger the edit's default error

* message as well. The second SAVE_TEXT message will be

* displayed between the first error message and the second.

*/

int t_cmp;

if (!INLIST(#S"Vital Status", "0,1"))

SAVE_ERROR_TEXT(293);

t_cmp = strcmp(#S"Vital Status", "1");

if (t_cmp == 0)

{

SAVE_TEXT("Patient is alive");

return PASS;

}

else

{

SAVE_TEXT("Patient is deceased or Vital Status unknown");

return FAIL;

}


Detailed Descriptions

SAVE_TEXT

Generates messages but does not set error flags.
Syntax | SAVE_TEXT(string)
Description | Generates messages but does not set error flags. This function causes FAIL to be returned from the edit. Messages reported by SAVE_TEXT are in addition to any reported by ERROR_MSG or other returns from the edit.
Return value | None
See Also | ERROR_TEXT, ERROR_MSG, SAVE_ERROR_TEXT, SAVE_WARNING_TEXT
Example | /* This example demonstrates the subtle differences between * using SAVE_TEXT and ERROR_TEXT. */ int mo_day; char datestring[20], datenum[3]; /* This message simply announces the purpose of the edit */ SAVE_TEXT("Testing if birth month = 11"); mo_day = DATE_MONTH_IOP(#S"Date of Birth"); strcpy(datestring, "Birth Month is "); fmtstr(datenum,"%02ld",mo_day); strcat(datestring, datenum); if (mo_day == 11) { SAVE_TEXT(datestring); /* If you return FAIL here, both the SAVE_TEXT message * and the edit's default error message will display. * However, if you return PASS here, only the * SAVE_TEXT message will display. */ return FAIL; } else { ERROR_TEXT(datestring); /* You MUST return FAIL after invoking ERROR_TEXT, * or the error message will not be displayed. */ return FAIL; }


Detailed Descriptions

SAVE_WARNING_TEXT

Generates warning messages but does not set flags.
Syntax | int SAVE_WARNING_TEXT(msg1 [, msg2 [...msg3]])
Description | Generates warning messages but does not set flags. This function causes WARN to be returned from the edit. It can be used to return multiple warning or error messages from the same edit, unlike ERROR_MSG, which changes the default error message only. Warnings reported by SAVE_WARNING_TEXT are in addition to any reported by ERROR_MSG or other returns from the edit.
Return value | None
See Also | ERROR_TEXT, SAVE_TEXT, SAVE_ERROR_TEXT, ERROR_MSG, SET_ERROR, SET_WARNING
Example | if(empty(#S"Birth Date") SAVE_WARNING_TEXT(302); else ...


Detailed Descriptions

SET_WARNING

Sets specified flags and generates error messages.
Syntax | int SET_WARNING(flag1 [, flag2 [...flagn]])
Description | Sets one or more flags in the flag_array and generates corresponding error messages. This function causes WARN to be returned from the edit. It can be used to return multiple warning or error messages from the same edit, unlike ERROR_MSG, which changes the default error message only. Warnings reported by SET_WARNING are in addition to any reported by ERROR_MSG or other returns from the edit.
Return value | None
Example | if (empty(#S"Birth Date") SET_WARNING(302); else ...


Detailed Descriptions

SETVAR

Creates and/or sets value of a common variable.

Syntax

SETVAR(var_name,value [, element])

Description

This EDITS language function will set (creating, if necessary) a common variable specified by name 'var_name' and an optional array element 'element' to the character value 'value'.

Common variables are variables that are shared between the calling program and the EDITS language. The API can get and set common variables via calls to EEx_GetVar, EEx_GetVarIndex, EEx_SetVar, and EEx_SetVarIndex. These variables can be accessed within the EDITS language by calls to GETVAR and SETVAR.

To clear a common variable or common variable array, call setvar with the name of the variable or array and an empty argument ("".) When clearing all elements of an array, don't supply a subscript.

Some variables that can be set by SETVAR have special uses. GROUPBREAK can be set by an edit to enable group error summaries within GenEDITS.

BLANKFIRSTMONTHDIGIT can be set to "Y" to allow VALID_DATE to pass dates where the month is not zero-filled. VALID_DATE is a deprecated function; this behavior is not supported in VALID_DATE_IOP.

Return value

None

See Also

GETVAR

Example

SETVAR("Status","DONE");


Detailed Descriptions

STRCAT

Concatenates (appends) one string to another.
Syntax | char *STRCAT(str1, str2 [,num])
Description | STRCAT concatenates num characters of str2 onto the end of str1; num specifies how many characters to concatenate. If num is not passed, all of str2 is concatenated.
Return value | Returns str1 with str2 concatenated.
Example | /* Concatenate State and Zip Code to search for valid * combination. #S"State" is "GA", #S"Zip Code" is "30341" */ char searchstr[8]; STRCPY(searchstr,#S"State"); /* searchstr contains "GA" */ STRCAT(searchstr,#S"Zip Code"); /* searchstr contains "GA30341" */ if(ILOOKUP(searchstr,"ZIPCODE.DBF.STATEZIP")) return PASS; ... /* STATEZIP is an index of valid state and zip code * concatenations */


Detailed Descriptions

STRCMP

Compares one string to another.
Syntax | int STRCMP(str1, str2 [,num])
Description | STRCMP compares the contents of the first num characters of str1 and str2. The comparison is case-sensitive. If num is not passed, the full strings are compared.
Return value | Str1 == Str2 : 0 Str1 < Str2 : -1 Str1 > Str2 : 1
See Also | INLIST, MATCH
Example | /* #S"State" is "GA", #S"Zip Code" is "30341" */ char t_state[3], t_state_zip[8]; STRCPY(t_state, #S"State"); STRCPY(t_state_zip, #S"State"); /* t_state and t_state_zip each contain "GA" */ STRCAT(t_state_zip, #S"ZipCode"); /* t_state_zip contains "GA30341" */ /* compare the entire contents of t_state to "GA" */ if (not STRCMP(t_state, "GA")==0) return FAIL; /* compare just the first 2 characters of t_state_zip to "GA" */ if (not STRCMP(t_state_zip, "GA", 2) == 0) return FAIL;


Detailed Descriptions

STRCPY

Copies the contents of source to destination.
Syntax | STRCPY(dest, source [,[-]num])
Description | STRCPY copies the contents of source to destination, based on num. If num is not specified, source is copied in its entirety. If num is positive, source is copied up to the num'th character. If num is negative, source is copied up to the num'th character and padded with blanks as necessary to reach num characters.
Return value | dest, the destination string.
Example | char dest[20]; char source[20]; strcpy(source,"Hello, World"); strcpy(dest,source); /* dest gets "Hello, World" */ strcpy(dest,source,10); /* dest gets "Hello, Wor" */ strcpy(dest,source,15); /* dest gets "Hello, World" */ strcpy(dest,source,-15); /* dest gets "Hello, World " */


Detailed Descriptions

STRLEN

Counts how many characters are in a string.
Syntax | int STRLEN(string|field)
Description | STRLEN returns how many characters are in string. (Trailing blanks are not counted.)
Return value | Returns length of string.
Example | int n; n=STRLEN(#S"State");


Detailed Descriptions

SUBSTR

Returns a substring of a string.
Syntax | char *SUBSTR(string|field, start_pos [,num_chars])
Description | Returns a pointer to a substring, beginning at startpos for length num_chars. If num_chars not passed, the remainder of the string is returned (with trailing blanks removed!). Start_pos references the first character as 1, not 0.
Return value | Returns a substring.
Example | char str1[30], str2[20]; STRCPY(str1, "Hello World "); STRCPY(str2, SUBSTR(str1, 6, 12)); /* str2 gets " World " */ STRCPY(str2, SUBSTR(str1, 1, 5)); /* str2 gets "Hello" */ STRCPY(str2, SUBSTR(str1, 5, 3)); /* str2 gets "o W" */


Detailed Descriptions

TRIM

Removes leading and/or trailing spaces.

Syntax

char *TRIM(string|field, LEFT | RIGHT | BOTH )

Description

TRIM removes leading (LEFT) or trailing (RIGHT) spaces, or both (BOTH) from a string or field and returns a trimmed copy. The original is left unchanged.

The string returned from TRIM can be captured only by embedding it in a call to a string handling function such as STRCPY, STRCAT or SUBSTR.

Return value

Returns a copy of trimmed string.

See Also

STRCPY, STRCAT, SUBSTR, STRLEN

Example

char str1[30], str2[20];

STRCPY(str1, " Hello ");

STRCPY(str2, TRIM(str1, LEFT)); /* str2 gets "Hello " */

STRCPY(str2, TRIM(str1, RIGHT)); /* str2 gets " Hello " */

STRCPY(str2, TRIM(str1, BOTH)); /* str2 gets " Hello " */

int t_len;

t_len = STRLEN(TRIM(str1, BOTH)); /* t_len == 5 */


Detailed Descriptions

UPPER

Converts string to upper case.

Syntax

char *UPPER(string|field)

Description

Returns a copy of a string with all lower case characters converted to upper case. The original is left unchanged.

The return string must be captured by embedding this function call within a string handling function such as STRCPY, STRCAT, SUBSTR, etc.

Return value

Returns a copy of upper case string.

See Also

LOWER

Example

char str1[30], str2[20];

STRCPY(str1, "Hello");

STRCPY(str2, UPPER(str1)); /* str2 gets "HELLO" */


Detailed Descriptions

USRn(n=1-10)

Calls a developer-defined function written in C.

Syntax

USRn([val1, ... val5])

Description

Note: This description is correct only if the application that is running EDITS has statically linked the EDITS Engine source code. Since 99.99-100.00% of users of the EDITS Engine use the dynamic link library, this discussion is therefore nothing more than an interesting historical artifact. The notes about USR2 and USR4, however, continue to be correct.

There are provisions for defining up to 10 user functions, allowing the EDITS language to call C functions. The function names are USR1 ... USR10.

The C functions must be written to accept five long parameters and return a long value.

To be used from within the EDITS language, the C functions must be mapped into the array EE_usr_func as follows:

/* Function prototypes */

long myusr1(long l1, long l2, long l3, long l4, long l5);

...

long myusr10(long l1, long l2, long l3, long l4, long l5);

/* Function mapping */

EE_usr_func[0]=myusr1;

...

EE_usr_func[9]=myusr10;

All elements of EE_usr_func are initialized to NULL by EE_Init; mapping assignments must occur after EE_Init.

This functionality is available at runtime only when using the API library, or when using applications that have already incorporated USR functions when building the API.

Notes

Several standard cancer edits incorporate the following USR functions:

USR2 Sets flags indicating part of an edit has failed (and triggers an error message - used to override the EDITS model of one error message at a time returned from an edit.)

USR4 Checks flags set by USR2 (or error message numbers in range of 251-475). If any listed flag is set, returns TRUE.

These USR functions are incorporated into the EDITS Dynamic Link Library.

Return value

Integer

Example

if ( USR4( 262, 270, 301, 303 ))

return PASS;

...


Detailed Descriptions

VAL

Returns the numeric value of an ASCII string.
Syntax | long VAL(string|field)
Description | Returns the numeric value of an ASCII string.
Return value | Long integer, numeric value of a string
Example | long zip; zip=VAL( #S"Zip Code" );


Detailed Descriptions

VALID_DATE_IOP

Checks date for validity.

Syntax

int VALID_DATE_IOP(string | field)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The following date formats will return TRUE (assuming the values in each date component fall within legitimate ranges):

CCYYMMDD | Century+Year, Month and Day are provided.
CCYYMM__ | Century+Year and Month. Day consists of two blank spaces.
CCYY____ | Century+Year. Month and Day consist of four blank spaces.

Note that if the input date is an empty string this function will return FALSE. In some circumstances it is valid for a date field to be empty. However, it is the responsibility of the author of the edit to write the code to test for EMPTY and take appropriate action.

Dates are checked first to ensure they conform to one of these formats, then for errors in the components. Checking stops on the first non-valid situation so that a date component in error will cause this function to return FALSE.

When a date is not valid, the %DC (Date Component) error message macro can be used to supply text detailing the problem with the date.

Possible text substitutions are:

"invalid as to day"

"invalid as to month"

"invalid as to year"

"date type must be D1"

"date is an empty string"

Range checking:

Lowest allowed value: January 1, 1850 (or in D1 format: 18500101)

Highest allowed value: Current system date. If the edit contains a previous call to ALLOW_FUTURE_DATE_IOP, the highest allowed value is current system date + years_into_future.

When month is known, it is checked to ensure it falls within range 01...12.

When month and day are known, day is checked to ensure it falls within range for that specific month. Accommodation is made for leap years.

Return value

TRUE | Those parts of the date that are present are valid.
FALSE | Century+Year, Month or Day is out of range, or non-numeric values. Month and Day must have leading zeros for values 01..09. An empty date (i.e., a date consisting of eight blank spaces) is considered NOT valid.

Example

/* EXAMPLE 1:

* Verify that Date of Diagnosis conforms to formatting rules

*/

if (not VALID_DATE_IOP(#S"Date of Diagnosis"))

{

error_text("Date of Diagnosis error: %DC");

return FAIL;

}

/* EXAMPLE 2:

* Allow for a scheduled treatment up to a year into the future

*/

ALLOW_FUTURE_DATE_IOP(1);

if (VALID_DATE_IOP(#S"Date Radiation Planned"))

{

save_text("Date Radiation Planned is scheduled appropriately");

return PASS;

}

else

{

error_text("Date Radiation Planned error: %DC");

return FAIL;

}


Detailed Descriptions

YEARDIFF_IOP

Find the difference between two dates, counted in years.

Syntax

int YEARDIFF_IOP(begDt, endDt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

Calculates the difference between two dates, counted in years. A year is calculated by counting the number of days between begDt and endDt, and dividing the result by 365. Note that the function rounds down; 1825 days returns 5 years, but 1824 days returns 4 years.

The third parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

The difference in dates may be negative if begDt is after endDt.

Return value

If the input dates are valid, this function returns the number of years between the dates.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and/or day portion of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

/* This edit will compare Date of Conclusive DX to

* Date of Last Contact to identify cases where patient

* survived for at least 5 years.

*/

int yy_cdx, yy_dx;

int years_diff;

yy_cdx = DATE_YEAR_IOP(#S"Date of Conclusive DX");

yy_dx = DATE_YEAR_IOP(#S"Date of Last Contact");

/* Check for basic validity */

if (yy_cdx == DT_ERROR || yy_cdx == DT_EMPTY)

{

error_text("Date of Conclusive DX error: %DC");

return FAIL;

}

if (yy_dx == DT_ERROR || yy_dx == DT_EMPTY)

{

error_text("Date of Last Contact error: %DC");

return FAIL;

}

/* Evaluate two dates that may or may not have the month and day

* portions. Allow the maximum window for comparison.

*/

years_diff = YEARDIFF_IOP(#S"Date of Conclusive DX",

#S"Date of Last Contact", DT_MAX);

if (years_diff >= 5)

return PASS;

else

{

error_text("May not have survived at least 5 years from DX.");

return WARN;

}


Detailed Descriptions

YEARINTERVAL_IOP

Checks to see if two dates fall within an interval, counted in years, of each other.

Syntax

int YEARINTERVAL_IOP(begDt, endDt, minInt, maxInt, min_max_flag)

Description

This function accepts dates using D1 format only (CCYYMMDD).

The function first determines whether either of the input dates is an empty string. If so, the function returns DT_EMPTY.

The function then determines whether the input dates are valid (see VALID_DATE_IOP). If either date is not valid, this function returns DT_ERROR.

YEARINTERVAL_IOP calculates the number of years between begDt and endDt. (A year is calculated by counting the number of days between begDt and endDt, and dividing the result by 365. Note that the function rounds down; 1825 days returns 5 years, but 1824 days returns 4 years.) If that calculated value is greater than or equal to minInt and less than or equal to maxInt, the function returns TRUE. If it falls outside that range, the function returns FALSE.

The fifth parameter, min_max_flag, is used by the function only when the month or day part of a date is missing. The flag specifies how to handle missing values by one of DT_MIN, DT_MAX or DT_EXACT.

When the Month part of a date is missing:

If DT_MIN is specified, the function assumes December for begDt. If year portion is the same for both dates and month portion is missing for endDt, the function assumes the endDt month is the same as begDt month; otherwise, it assumes January for endDt.

If DT_MAX is specified, the function assumes January for begDt, and December for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

When the Day part of a date is missing:

If DT_MIN is specified, the function assumes the last day of the month for begDt, and the first day of the month for endDt. If the year and month portions are the same for both dates and the day portion is missing for endDt, the function assumes the endDt day is the same as the begDt day; otherwise it assumes the first day of the month for endDt.

If DT_MAX is specified, the function assumes the first day of the month for begDt, and the last day of the month for endDt.

If DT_EXACT is specified, the function returns DT_UNKNOWN.

Return value

If the input dates are valid:

TRUE | if begDt and endDt are within the interval.
FALSE | if the interval between the dates exceeds the difference between minInt and maxInt.

If either of the input dates is an empty string, this function returns DT_EMPTY.

If the month and day portions of either of the input dates is blank, and the min_max_flag is DT_EXACT, this function returns DT_UNKNOWN.

If either of the input dates is not valid, this function returns DT_ERROR.

Example

int is_within_interval;

is_within_interval = YEARINTERVAL_IOP(#S"Date of Diagnosis",

#S"Date Conclusive DX", 0, 3, DT_EXACT);

/* ALWAYS check date IOP functions for error code! */

if (is_within_interval == DT_ERROR)

{

/* Find out which date is invalid */

if (!VALID_DATE_IOP(#S"Date of Diagnosis"))

error_text("Date of Diagnosis error: %DC");

else

{

if (!VALID_DATE_IOP(#S"Date Conclusive DX"))

error_text("Date Conclusive DX error: %DC");

}

return FAIL;

}

if (is_within_interval)

error_text("Date Conclusive Dx is within 3 years of Date Dx");

else

error_text("Date Conclusive Dx is outside 3 year window");

return FAIL;


CHECK_FLAG

Detailed Descriptions

CHECK_FLAG (deprecated)

Functions Check_Flag, Clear_Flags, Incr_Flag, Set_Error and Set_Flag were introduced to the EDITS Language early in the development of these tools. They had a specific use for an era that has passed. Please do not use them in new edits, and remove them from any existing edits. They will eventually be removed from the EDITS Language.

Checks specified flags in flag array.
Syntax | int CHECK_FLAG(flag1 [, flag2 [...flagn]])
Description | Checks all flags specified in the function call. CHECK_FLAG is a formal implementation of a flag array, allowing some edits to set flags on failure and other edits to check those flags.
Return value | If any flag in the parameter list is non-zero, returns TRUE. Otherwise, returns FALSE.
See Also | SET_FLAG, CLEAR_FLAGS
Example | if (CHECK_FLAG(302,305,306)) return PASS; ...


CLEAR_FLAGS

Detailed Descriptions

CLEAR_FLAGS (deprecated)

Functions Check_Flag, Clear_Flags, Incr_Flag, Set_Error and Set_Flag were introduced to the EDITS Language early in the development of these tools. They had a specific use for an era that has passed. Please do not use them in new edits, and remove them from any existing edits. They will eventually be removed from the EDITS Language.

Clears all flags in the flag array.
Syntax | void CLEAR_FLAGS()
Description | Clears all flags in the flag array. All flags are set to zero.
Return value | None
See Also | CHECK_FLAG, SET_FLAG
Example | CLEAR_FLAGS();


COPYRECORD

Detailed Descriptions

COPYRECORD (deprecated)

This function does not work as documented. If you have a need for such a function, please submit specifications and we will consider implementing it.

Copies fields from one record layout into another

Syntax

COPYRECORD(dest_rec_layout, source_rec_layout)

Description

Copies fields from one record layout into another. This function can be used to reformat data. Only fields that are defined in the source and destination are copied. Fields that differ in type are converted to the new type where possible. Dates are converted as well. If the source format does not carry the century but the destination uses it, ”19" will be assumed. If the source format does not have carry day (year and month only), ”99" will be assumed (missing value for day).

Some format conversions will require more than changing positions. For these, COPYRECORD can be called initially to move what can be moved, then programmatic recoding (using PUTFIELD) can adjust fields that need it.

Return value

None

Example

To convert records from the SEER format to NAACCR format:

Create an edit with this in it.

COPYRECORD("NAACCR","SEER");

Create an edit set with this edit in it.

In GenEDITS, select SEER as the Record Layout. Select the edit set with COPYRECORD in it. On the Output and Recoding Screen (Window/Advanced Options/Output and Recoding), put the name for the NAACCR format output in the Recoded Output Data File blank. Supply an appropriate Recoded Output Record Length. Select the NAACCR record layout as the Recoded Output Record Layout. GenEDITS will write all Recoded Records to the Recoded Output Data File.


DATE_DAY

Detailed Descriptions

DATE_DAY (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DATE_DAY_IOP instead.

Returns day portion of date
Syntax | int DATE_DAY(date)
Description | Returns day of month portion of a date
Return value | Numeric, day of month (1-31)
See Also | DATE_MONTH, DATE_YEAR (both are also deprecated)
Example | int mo_day; mo_day=DATE_DAY(#S"Birth Date");


DATE_MONTH

Detailed Descriptions

DATE_MONTH (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DATE_MONTH_IOP instead.

Returns month portion of date
Syntax | int DATE_MONTH(date)
Example Call | month=DATE_MONTH(#S"Birth Date")
Description | Returns month portion of date
Return value | Numeric, month of year (1-12)
See Also | DATE_YEAR, DATE_DAY (both are also deprecated)
Example | int month; month=DATE_MONTH(#S"Birth Date");


DATE_YEAR

Detailed Descriptions

DATE_YEAR (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DATE_YEAR_IOP instead.

Returns year portion of date
Syntax | int DATE_YEAR(date)
Description | Returns year portion of date
Return value | Numeric, year
See Also | DATE_MONTH, DATE_DAY (both are also deprecated)
Example | int year; year=DATE_YEAR(#S"Birth Date");


DATECMP

Detailed Descriptions

DATECMP (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DATECMP_IOP instead.

Compares two dates by subtracting date2 from date1.
Syntax | int DATECMP(date1, date2)
Description | Compares two dates by subtracting date2 from date1. Date types may be mixed for comparison, as all date types are converted to a common internal format for operations. Date constants should be specified as quoted strings in either "mm/dd/ccyy"or "ccyymmdd" format. For example, January 31, 1982, would be written as "01/31/1982" or "19820131".
Return value | Numeric: 1 if date 1 > date 2 0 if date 1 = date 2 -1 if date 1 < date 2
Example | diff=DATECMP(#S"Birth Date", #S"Date of Diagnosis");


DAYDIFF

Detailed Descriptions

DAYDIFF (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DAYDIFF_IOP instead.

Use DayDiff to find the difference in days between two dates.
Syntax | int DAYDIFF(begDt, endDt, min_max_flag)
Description | Returns the difference between two dates. The third parameter, min_max_flag, specifies how to handle missing values by one of DT_EXACT, DT_MIN, or DT_MAX. If DT_EXACT is specified, DT_UNKNOWN will be returned if any part of a date is missing. When part of a date is missing and DT_MIN or DT_MAX is specified, the minimum or maximum difference is returned if possible, otherwise, DT_UNKNOWN is returned. The difference in dates may be negative if begDt is after endDt.
Return value | Numeric, difference between begDt and endDt.
See Also | MONTHDIFF, YEARDIFF (both are also deprecated)
Example | diff=DAYDIFF(#S"Birth Date", #S"Date of Diagnosis", DT_EXACT);


DAYINTERVAL

Detailed Descriptions

DAYINTERVAL (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use DAYINTERVAL_IOP instead.

Checks to see if two dates are within a minimum or maximum number of days of each other.
Syntax | int DAYINTERVAL(begDt, endDt, minInt, maxInt, DT_MIN | DT_MAX | DT_EXACT)
Description | DAYINTERVAL checks intervals specified in units of days. The third parameter, min_max_flag, determines how to handle missing values. DT_MIN, DT_MAX, DT_EXACT are defined within the Edit Engine.
Return value | TRUE if begDt and endDt are within the interval FALSE if outside the interval or unknown.
See Also | MONTHINTERVAL, YEARINTERVAL (both are also deprecated)
Example | diff=DAYINTERVAL(#S"Birth Date", #S"Date of Diagnosis", 5, 10, DT_EXACT);


INCR_FLAG

Detailed Descriptions

INCR_FLAG (deprecated)

Functions Check_Flag, Clear_Flags, Incr_Flag, Set_Error and Set_Flag were introduced to the EDITS Language early in the development of these tools. They had a specific use for an era that has passed. Please do not use them in new edits, and remove them from any existing edits. They will eventually be removed from the EDITS Language.

Sets one or more flags without generating a message.
Syntax | int INCR_FLAG(flag1 [, flag2 [...flagn]])
Description | Increments the value of one or more flags in the flag_array, but does not save message text in the errors_found_array.
Return value | None
See Also | CHECK_FLAG, SET_FLAG, CLEAR_FLAGS
Example | if(empty(#S"Birth Date") INCR_FLAG(302); else ...


MONTHDIFF

Detailed Descriptions

MONTHDIFF (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use MONTHDIFF_IOP instead.

Returns the difference between two dates in months.
Syntax | int MONTHDIFF(begDt, endDt, min_max_flag)
Description | Returns the difference between two dates in months. The third parameter, min_max_flag, specifies how to handle missing values by one of DT_EXACT, DT_MIN, or DT_MAX. If DT_EXACT is specified, DT_UNKNOWN will be returned if any part of a date is missing. When part of a date is missing and DT_MIN or DT_MAX is specified, the minimum or maximum difference is returned if possible; otherwise, DT_UNKNOWN is returned. The difference in dates may be negative if begDt is after endDt.
Return value | Numeric, difference between dates in months.
See Also | DAYDIFF, YEARDIFF (both are also deprecated)
Example | diff=MONTHDIFF(#S"Birth Date", #S"Date of Diagnosis", DT_EXACT);


MONTHINTERVAL

Detailed Descriptions

MONTHINTERVAL (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use MONTHINTERVAL_IOP instead.

Checks to see if two dates are within a minimum or maximum number of months of each other.
Syntax | int MONTHINTERVAL(begDt, endDt, minInt, maxInt, DT_MIN | DT_MAX | DT_EXACT)
Description | MONTHINTERVAL checks intervals specified in units of months. The third parameter, min_max_flag, determines how to handle missing values. DT_MIN, DT_MAX, and DT_EXACT are defined within the Edit Engine.
Return value | TRUE if begDt and endDt are within the interval. FALSE if outside the interval or unknown.
See Also | DAYINTERVAL, YEARINTERVAL (both are also deprecated)
Example | diff=MONTHINTERVAL(#S"Birth Date", #S"Date of Diagnosis", 6, 12, DT_EXACT);


Detailed Descriptions

READ (deprecated)

This function does not work as documented, and as far as we can tell, it never did. As of v4.0 of the EDITS Engine, any call to this function will result in error message 523: call_read never worked; submit specifications. If you have a need for such a function, please submit your specifications and we'll consider it.

Reads a .DBF table record sequentially or directly by record number.
Syntax | READ( [record_number] )
Description | Reads a .DBF table record sequentially or directly by record number, if specified. The table must have already been opened by USE. As the record is read, each field becomes a variable that may be referenced within the edit. This function is most useful when you want to retrieve a specific record by its record number (same as its position in the table.)
Return value | TRUE if a record is retrieved; FALSE otherwise.
See Also | USE
Example | if(READ( recnum )) ...


RECORDEMPTY

Detailed Descriptions

RECORDEMPTY (deprecated)

We believe the scenario described here is specious. The EDITS Engine has no mechanism for dynamically disabling an edit set based upon the return value of an edit.

Checks a record layout for the presence of data.
Syntax | int RECORDEMPTY(record_layout_number)
Description | RECORDEMPTY checks all fields in a record layout for the presence of data. This function is useful for checking the contents of a record or subrecord for data before editing it. A control edit could use this function to decide whether to disable an edit set if a record or subrecord has no data.
Return value | FALSE if data found in any field of record layout; TRUE otherwise.
Example | if ( RECORDEMPTY( 2 ) == FALSE ) return PASS;


SET_ERROR

Detailed Descriptions

SET_ERROR (deprecated)

Functions Check_Flag, Clear_Flags, Incr_Flag, Set_Error and Set_Flag were introduced to the EDITS Language early in the development of these tools. They had a specific use for an era that has passed. Please do not use them in new edits, and remove them from any existing edits. They will eventually be removed from the EDITS Language.

Sets specified flags and generates error messages.
Syntax | int SET_ERROR(flag1 [, flag2 [...flagn]])
Description | Sets one or more flags in the flag_array and generates corresponding error messages. This function causes FAIL to be returned from the edit. It can be used to return multiple error messages from the same edit, unlike ERROR_MSG, which changes the default error message only. Errors reported by SET_ERROR are in addition to any reported by ERROR_MSG or other returns from the edit.
Return value | None
See Also | CHECK_FLAG, SET_FLAG, INCR_FLAG, CLEAR_FLAGS
Example | if (empty(#S"Birth Date") SET_ERROR(302); else ...


SET_FLAG

Detailed Descriptions

SET_FLAG (deprecated)

Functions Check_Flag, Clear_Flags, Incr_Flag, Set_Error and Set_Flag were introduced to the EDITS Language early in the development of these tools. They had a specific use for an era that has passed. Please do not use them in new edits, and remove them from any existing edits. They will eventually be removed from the EDITS Language.

Sets a flag to specific value.
Syntax | int SET_FLAG( flag1, value )
Description | Sets a flag in the flag_array to a specific value. Does not cause an error message. When a flag is set in one edit, it can be checked by another within the same edit set. See CHECK_FLAG.
Return value | None
See Also | SET_ERROR, CHECK_FLAG, INCR_FLAG, CLEAR_FLAGS
Example | if (empty(#S"Birth Date") SET_FLAG(302,1); else ...


Detailed Descriptions

USE (deprecated)

This function does not work as documented, and as far as we can tell, it never did. As of v4.0 of the EDITS Engine, any call to this function will result in error message 522: call_use never worked; submit specifications. If you have a need for such a function, please submit your specifications and we'll consider it.

Opens a table for sequential or direct access by record number.
Syntax | USE( table_name )
Description | Opens a .DBF table for sequential or direct access by record number. This function prepares for table access by the READ function and is most useful when you want to retrieve a specific record by its record number (same as its position in the file.)
Return value | None
See Also | READ
Example | USE("SPECIAL.DBF") ...


YEARDIFF

Detailed Descriptions

YEARDIFF (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use YEARDIFF_IOP instead.

Returns the difference between two dates in years.
Syntax | int YEARDIFF(begDt, endDt, min_max_flag)
Description | Returns the difference between two dates in years. The third parameter, min_max_flag, specifies how to handle missing values by one of DT_EXACT, DT_MIN, or DT_MAX. If DT_EXACT is specified, DT_UNKNOWN will be returned if any part of a date is missing. When part of a date is missing and DT_MIN or DT_MAX is specified; the minimum or maximum difference is returned if possible, otherwise, DT_UNKNOWN is returned. The difference in dates may be negative if begDt is after endDt.
Return value | Numeric, difference in years between dates.
See Also | DAYDIFF, MONTHDIFF
Example | diff=YEARDIFF(#S”Birth Date”, #S”Date of Diagnosis”, DT_EXACT);


YEARINTERVAL

Detailed Descriptions

YEARINTERVAL (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use YEARINTERVAL_IOP instead.

Checks to see if two dates are within a minimum or maximum number of years of each other.
Syntax | int YEARINTERVAL(begDt, endDt, minInt, maxInt, min_max_flag)
Description | YEARINTERVAL checks intervals specified in units of days. The third parameter, min_max_flag, determines how to handle missing values. DT_MIN, DT_MAX, and DT_EXACT are defined within the Edit Engine.
Return value | TRUE if begDt and endDt are within the interval FALSE if outside the interval or unknown.
See Also | MONTHINTERVAL, DAYINTERVAL
Example | diff=YEARINTERVAL(#S"Birth Date", #S"Date of Diagnosis", 5, 10, DT_EXACT);


VALID_DATE

Detailed Descriptions

VALID_DATE (deprecated)

This function has been deprecated, and should not be used for editing cases coded in NAACCR v12 or later. It will be retained for backward compatibility. Please use VALID_DATE_IOP instead.

Checks date for validity.

Syntax

int VALID_DATE(string | field)

Description

Checks validity of a DATE.

Dates are checked first for errors, then for missing pieces, and finally for unknown components. Within this order, year is checked, then month, then day. Checking stops on the first non-valid situation so that a date component in error will cause a DT_ERROR, even if another component is missing or unknown.

When a date is not DT_VALID, the %DC (Date Component) error message macro can be used to supply text detailing the problem with the date.

Possible text substitutions are:

"invalid as to day"

"invalid as to month"

"invalid as to year"

"missing the day"

"missing the month"

"missing the year"

"unknown as to day"

"unknown as to month"

"unknown as to year"

When month and day are known, day is checked for within range for that specific month, leap year included.

If month is unknown, day must be 31 or less.

If year is unknown, Feb 29 is allowed in case of leap year.

Allowed values for year are:

Lowest Allowed Value: Current (system) year - 150

Highest Allowed Value: Current (system) year + 5

Valid_Date expects digits to be present in all positions of the date and will normally report errors if the month is not zero-filled. To allow blanks in the first character of the month, call EDITS API function EE_SetVar or language function SetVar.

Ex: EE_SetVar("BLANKFIRSTMONTHDIGIT","Y");

Return value

DT_VALID All parts of date are present and valid

DT_MISSING Some component of date is missing (00)

DT_UNKNOWN Some component of date is unknown (99)

DT_ERROR Month or Day is out of range, or non‑numeric values (must have leading zeros where appropriate)

Example

In this example, Return FAIL on Date Error or Date Missing.

Return WARN on Date Unknown.

int retval;

/* Assign result of VALID_DATE to variable so the function does not have to be called repeatedly. */

retval=VALID_DATE(#S"Date Type 3");

if (retval==DT_ERROR)

{

error_text("Date Error: %DC");

return FAIL;

}

if (retval==DT_MISSING)

{

error_text("Date Missing: %DC");

return FAIL;

}

if (retval==DT_UNKNOWN)

{

error_text("Date Unknown: %DC");

return WARN;

}

if (retval==DT_VALID)

return pass;