Supporting user‑defined data type fields

You can define fields whose data type is user‑defined. These fields are treated as alpha fields in most cases, except when ReportWriter displays them. Every time ReportWriter needs to access a user‑defined field, it calls RW_USAGE_METHOD, RW_GETVAL_METHOD, or RPS_DATA_METHOD as follows:

You can register your own versions of these routines to provide the desired mechanisms for displaying and using user‑defined data type fields. These routines are ideal for supporting data types that are not supported directly or for supporting alternate date storage formats. (See the RW_USAGE_METHOD Examples.)

Note

If you use these routines to access data that is larger than the stored representation, ReportWriter will access the user‑defined field only as a field to print.

RW_USAGE_METHOD

subroutine RW_USAGE_METHOD
a_user_text     ,a      ;User text string associated with field (a80)
a_user_data     ,a      ;User data string associated with the field (a30)
a_type          ,n      ;Returned with the field's data type for
                        ; internal use (d1)
                        ; 0   No data type change.
                        ; 1   Alphanumeric.
                        ; 2   Decimal.
                        ; 3   Implied-decimal.
                        ; 4   Integer.
a_size          ,n      ;Returned with field length (d4)
a_precision     ,n      ;Returned with field's precision if internal 
                        ; type is implied-decimal (d2)
a_class         ,n      ;Returned with field's class and is one of
                        ; the following values (d1)
                        ; 0   Neither date nor time field.
                        ; 1-6 Date field.
                        ; 8-9 Time field.
                        ;These values correspond to date and time storage 
                        ; formats listed in your Repository User’s Guide.

Discussion

During file processing, ReportWriter calls this routine once for all user type data fields. The a_user_data and a_user_text strings, a_size, a_precision, and a_class are those that have been defined in the Repository for the selected field.

By default, user‑defined data type fields are treated as alpha fields. If you want ReportWriter to use a different data type internally when processing the field, you can modify the distributed version of this routine.

A_type, a_size, a_precision, and a_class tell ReportWriter how to treat the field internally when it is used in a calculation, selection, or conditional or when it is used for sorting or totaling. During report execution, ReportWriter calls RW_GETVAL_METHOD to convert the actual data in the user‑defined field each time it is referenced.

If this routine modifies the data type, when the field is displayed in ReportWriter, its data type will be shown as the internal data type, preceded by a “U”. For example, if the field was defined in the repository as a “U4” and this routine specifies its internal type to be decimal with a size of 4, it will be shown as “UD4”.

This routine is always passed a type value of 0. The version of this subroutine linked with the ReportWriter in your original distribution returns the a_type value unchanged, meaning that the user‑defined field will be treated as alpha. The default version of this subroutine also returns the a_size, a_precision, and a_class unchanged.

Examples

The following example supports a user‑defined data type field for dates stored as MMDDYY(YY).

; Filename:             usr.dbl
;
; Function:             Defines user-overloadable subroutines for 
;                       ReportWriter
;
subroutine rps_data_method
;
; Description: Formats user-defined data type fields
;
; Arguments:
;
    a_source            ,a      ;Source field data (a99)
    a_dest              ,a      ;RETURNED - Modified field data (a99)
    a_use               ,n      ;ReportWriter's use of data (see Notes) (d1)
    a_usrtxt            ,a      ;User text string associated with data (a80)
    a_usrdata           ,a      ;User data string associated with data (a30)
    a_format            ,a      ;Format string associated with field (a40)
;
; Notes:
;       ReportWriter calls this routine every time a user-defined
;       field is displayed. See the Repository User’s Guide for more
;       information on user-defined fields.
;
;       a_use:          When a_use is 0, the item is being output (printer,
;                       screen, or file). When a_use is not 0, the item is 
;                       being used to format an input window. 
;
.include "WND:tools.def"
record
    year2               ,a2     ;2-digit year
    year4               ,a4     ;4-digit year
    year                ,a4     ;Temporary storage for date (year)
    month               ,a2     ;Temporary storage for date (month)
    day                 ,a2     ;Temporary storage for date (day)
    date                ,a10    ;Temporary storage for date (entire)
    r_date              ,a10    ;Date returned from u_fmtdat
proc
    if (a_use)                  ;Format only for output
      xreturn
    if ^passed(a_format) then
      begin
        case (a_format) of
          begincase
            "MM-DD-YY ":
              call format1 
            "MM/DD/YYYY ":
              call format2
          endcase
        else
          a_dest = a_source     ;Default behavior of rps_data_method 
      end 
    else
      a_dest = a_source
    xreturn
format1,
    date = ^d(a_source(1:6)), "XXXXXX"
    xcall u_fmtdat(3, r_date, ^d(date),,, D_LEFT, 0, '-')
    if (r_date(3:1).ne.'-') then
      a_dest = "0" + r_date
    else
      a_dest = r_date
    return

format2,
    date = ^d(a_source(1:8)), "XXXXXXXX"
    xcall u_fmtdat(6, r_date, ^d(date),,, D_LEFT, 0, '/')
    if (r_date(3:1).ne.'/') then
      a_dest = "0" + r_date
    else
      a_dest = r_date
    return
endsubroutine
subroutine rw_usage_method
;
; Description: Determines user-defined data type usage
;
; Arguments:
;
    a_usrtxt            ,a      ;User text string associated with data (a80)
    a_usrdata           ,a      ;User data string associated with data (a30)
    a_type              ,n      ;RETURNED - field's data type for internal
                                ; usage (d1) (see Notes)
    a_size              ,n      ;RETURNED - field's length (d4)
    a_precision         ,n      ;RETURNED - Precision if internal type is
                                ; implied-decimal (d2)
    a_class             ,n      ;RETURNED  Field class (see Notes) (d1)
;
;Notes:
;       ReportWriter calls this routine every time a user-defined
;       field is selected in a report. See the Repository User’s Guide 
;       for more information on user-defined fields.
;
proc
    upcase a_usrdata 
    case (a_usrdata) of
      begincase
        "MMDDYY ":
          call usage1
        "MMDDYYYY":
          call usage2
      endcase
    else
      nop                       ;Default behavior of rw_getval_method
    xreturn
usage1,
    a_type = 2                  ;Decimal
    a_size = 6
    a_precision = 0
    a_class = 1                 ;YYMMDD
    return
usage2,
    a_type = 2                  ;Decimal
    a_size = 8
    a_precision = 0
    a_class = 2                 ;YYYYMMDD
    return
endsubroutine
subroutine rw_getval_method
;
;Description: Returns user-defined data type value
;
;Arguments:
;
    a_source            ,a      ;Source field data (a99)
    a_dest              ,a      ;RETURNED - Modified field data (a99)
    a_usrtxt            ,a      ;User text string associated with data (a80)
    a_usrdata           ,a      ;User data string associated with data (a30)
    a_type              ,n      ;Internal data type for the field (d1)
    a_size              ,n      ;Internal size of the field (d4)
    a_precision         ,n      ;Internal precision of the field if 
                                ; implied-decimal (d2)
;Notes:
;       ReportWriter calls this routine during report generation
;       for each user-defined data type field in each data record. 
;
;       This routine converts actual file data for user-defined fields
;       before ReportWriter uses them for calculating, selecting, 
;       sorting, totaling, or defining a conditional.
;
;       The values for each parameter are those returned from the 
;       RW_USAGE_METHOD routine when the user-defined field was selected.
;
record 
    syn_date1           ,d6     ;YYMMDD - Synergy/DE date format #1
     s_year1            ,d2 @syn_date1
     s_month1           ,d2 @syn_date1 + 2
     s_day1             ,d2 @syn_date1 + 4
record 
    syn_date2           ,d8     ;YYYYMMDD - Synergy/DE date format #2
     s_year2            ,d4 @syn_date2
     s_month2           ,d2 @syn_date2 + 4
     s_day2             ,d2 @syn_date2 + 6
record 
    my_date1            ,d6     ;MMDDYY - User-defined date format #1
     m_month1            ,d2 @my_date1
     m_day1              ,d2 @my_date1 + 2
     m_year1             ,d2 @my_date1 + 4
record 
    my_date2            ,d8     ;MMDDYYYY - User-defined date format #2
     m_month2            ,d2 @my_date2
     m_day2              ,d2 @my_date2 + 2
     m_year2             ,d4 @my_date2 + 4
record
    date_out            ,d8     ;Output for final date returned from dyadd
    date_in             ,a10    ;Temporary storage for date transfer
proc
    upcase a_usrdata 
    case (a_usrdata) of
      begincase
        "MMDDYY ":
          call getval1
        "MMDDYYYY":
          call getval2
      endcase
    else
      a_dest = a_source         ;Default behavior of RW_GETVAL_METHOD
    xreturn
getval1,
    date_in = ^d(a_source(1,6)), "XXXXXX"
    my_date1 = ^d(date_in) 
    s_year1 = m_year1 ;Transfer date information
    s_month1 = m_month1
    s_day1 = m_day1
    a_dest = syn_date1, "XXXXXX"
            return
getval2,
    date_in = ^d(a_source(1,8)), "XXXXXXXX"
    my_date2 = ^d(date_in) 
    s_year2 = m_year2           ;Transfer date information
    s_month2 = m_month2
    s_day2 = m_day2
    a_dest = syn_date2, "XXXXXXXX"
    return
endsubroutine 

RW_GETVAL_METHOD

subroutine RW_GETVAL_METHOD
a_source        ,a      ;Source field data
a_dest          ,a      ;Returned with modified field data
a_user_text     ,a      ;User text string associated with field (a80)
a_user_data     ,a      ;User data string associated with field (a30)
a_type          ,n      ;Internal data type for field (d1)
a_size          ,n      ;Internal size of field (d4)
a_precision     ,n      ;Internal precision of field if internal type
                        ; is implied-decimal (d2)

Discussion

During report generation, ReportWriter calls this routine once for each record for each user‑defined data type field selected in the report. The a_user_data and a_user_text strings and a_type, a_size, and a_precision are values that were returned from the RW_USAGE_METHOD routine when the user‑defined field was selected.

You can use this routine to convert the actual file data for user‑defined fields before ReportWriter uses them in a calculation, selection, or conditional or for sorting or totaling. The data value is retrieved as an alpha field with the contents in user storage format. RW_USAGE_METHOD converts this value to an alpha field that contains the Synergy DBL storage format for the type to which you are converting.

Avoid explicit casting (using the ^D or ^A functions or alpha = decimal format) in creating the field’s new type, as you may lose the sign of a decimal field by performing these conversions. Instead, use a decimal field overlaid with an alpha field, as follows, to convert the field to alpha format implicitly.

record
    decimal             ,d28
    dec_alpha           ,a28 @decimal
Note

ReportWriter does not support changing data size using these routines. In this situation, you should convert to a decimal or alpha field of the same size.

The version of this subroutine linked with ReportWriter in your original distribution returns the original data, unmodified, in a_dest.

Note the following restrictions:

Examples

See the RW_USAGE_METHOD Examples.

RPS_DATA_METHOD

subroutine RPS_DATA_METHOD
a_source        ,a      ;Source field data (a99)
a_dest          ,a      ;Returned with modified field data (a99)
a_use           ,n      ;Indicates ReportWriter's use for the data (d1)
                        ; 0   Output (screen, printer, or file).
                        ; 1   Input window.
a_user_text     ,a      ;User text string associated with the field (a80)
a_user_data     ,a      ;User data string associated with the field (a30)
a_format        ,a      ;(optional) Format string associated with field (a40)

Discussion

ReportWriter calls RPS_DATA_METHOD every time a user‑defined data type field is displayed. (However, this routine is not called when the user‑defined data type field is used as a sort field.) RPS_DATA_METHOD converts the storage format created by RW_GETVAL_METHOD into the format you want ReportWriter to display. Note that a format must be provided when you select a user‑defined data type to print, and it must have at least the number of characters you wish to display within the format.

If a_use contains a value of 0, a_source is a field being printed on a detail line or break line. If a_use is nonzero, a_source is the input in a question field or a selection criteria comparison value. The user text string, user data string, and format string can contain whatever data is required to process the field.

Date and time fields do not automatically use the ReportWriter (or Repository) formats to display dates and times; you must perform this conversion yourself. This display conversion can also be performed using UI Toolkit U_FMTDAT and U_FMTTIM subroutines.

Remember to access implied‑decimal fields as such before formatting, using the ^D function:

^d(a_source, precision)

The version of this subroutine linked with the ReportWriter in your original distribution returns the original data, unmodified, in a_dest.

Examples

Here’s a sample RPS_DATA_METHOD subroutine that formats the specified user‑defined data type field based on the specified format. Also see the RW_USAGE_METHOD Examples.

subroutine rps_data_method
;
; Description:          This subroutine formats the given user-defined data
;                       type field based on a format string stored in the 
;                       field's user text area. Otherwise, it uses 
;                       the format string passed.
; Arguments:
;
    a_srcdat            ,a      ;Input source data string
    a_dstdat            ,a      ;Output result data string
    a_use               ,a      ;Use for user-defined field
    a_usrtxt            ,a      ;User text string associated with source field
    a_dattyp            ,a      ;Data type string associated with source field
    a_fmtstr            ,a      ;Optional format string
; This example assumes the size of a_dstdat is big enough to load the 
; extra format characters. The destination size can be controlled by a 
; dummy format string size.
record
    ix                  ,d3
    t_dec               ,d18
    t_date1             ,d8 @t_dec
    t_date2             ,d6 @t_dec
proc
    if (a_use)                          ;Only format for output
      xreturn
    upcase a_usrtxt
    case a_usrtxt of
      begincase
        "USER DATE #1":
          begin
            t_date1 = %d(a_srcdat) ;Destination source length must be
            case a_usrtxt(16:3) of      ; enough
              begincase
                "--":
                  xcall s_bld(a_dstdat,,"%4d%a%2a%a%2a",
  &                           t_date1(1:4), a_usrtxt(16:3), 
  &                           t_date1(5:2), a_usrtxt(16:3), 
  &                           t_date1(7:2)) 
                "***":
                  xcall s_bld(a_dstdat,, "%a%4d%a%2a%a%2a%a",
  &                           a_usrtxt(16:3), t_date1(1:4), 
  &                           a_usrtxt(16:3), t_date1(5:2), 
  &                           a_usrtxt(16:3), t_date1(7:2), 
  &                           a_usrtxt(16:3))
              endcase
          end
        "USER DATE #2":
          begin
            t_date2 = %d(a_srcdat)  ;Destination source length must be 
            case a_usrtxt(16:3) of  ; enough
              begincase
                "--":
                  xcall s_bld(a_dstdat,,"%4d%a%2a%a%2a", 
  &                           t_date2(1:4), a_usrtxt(16:3), 
  &                           t_date2(5:2), a_usrtxt(16:3), 
  &                           t_date2(7:2)) 
                "***":
                  xcall s_bld(a_dstdat,, "%a%4d%a%2a%a%2a%a", 
  &                           a_usrtxt(16:3), t_date2(1:4), 
  &                           a_usrtxt(16:3), t_date2(5:2), 
  &                           a_usrtxt(16:3), t_date2(7:2), 
  &                           a_usrtxt(16:3))
              endcase
          end
      endcase
    else
      if (%passed(a_fmtstr)) then                       ;Can use format string to
        if (%instr(1, a_fmtstr, "&") then               ; control format operation
           begin
             clear ix
             do                         ;For all blanks, replace with "*"
               begin
                                                         incr ix
                 if (a_srcdat(ix:1).eq." ") then
                   a_dstdat(ix:1) = "*"
                 else
                   a_dstdat(ix:1) = a_srcdat(ix:1)
               end
             until (ix.eq.%len(a_srcdat))
           end
        else
          a_dstdat = a_srcdat
      else
        a_dstdat = a_srcdat
    xreturn
endsubroutine