Initializing help system before first use

Type-related functions

Topics covered in this section:

In this example, the following structure represents a task:

typedef struct Task
     {
      int refcnt;
      const char *name;
      int aflag, duedate;
      double duration;
      struct Task *next;
     } s_task;

The first entry of this structure is the reference counter (with the flag XPRM_DTYP_RFCNT set at the type definition we have indicated that our module implements reference counting for the type `task'). The next four entries of this structure correspond directly to the information associated with a task (name, a Boolean flag, due date, duration). The last entry (next) points to the following element in the list of tasks held by the module context.

In the definition of the new type task, we have indicated the names of 5 functions for creating and deleting the new type, getting a textual representation and initializing the new type from a textual representation, and copying the type. The only function that is always required for any type definition is the creation function, the remaining ones are optional (for the deletion function depending on the type properties).

Type creation and deletion

The objective of the type instance creation and deletion functions is to handle (create/initialize or delete/reset) the C structures that represent the external type and to update correspondingly the information stored in the module context. In this example we implement just a rudimentary memory management for the objects (tasks) created by the module: every time a task is created, we allocate the corresponding space and deallocate it when the task is deleted. In Chapter Creating external types: second example a more realistic example is given that allocates chunks of memory and recycles space that has been allocated earlier by the module.

Reference counting: the flag XPRM_DTYP_RFCNT set at the type definition indicates that our module handles reference counting for the type task. As a consequence Mosel may call the type creation function with a reference to a previously created object for increasing its reference count. The type deletion function (which is mandatory in this case) is called as many times as the creation function has been used for a given object before this object is effectively released.

We define the task creation function as follows:

static void *task_create(XPRMcontext ctx, void *libctx, void *todup,
                         int typnum)
{
 s_taskctx *taskctx;
 s_task *task;

 if(todup!=NULL)
 {
  ((s_task *)todup)->refcnt++;
  return todup;
 }
 else
 {
  taskctx=libctx;
  task=(s_task *)malloc(sizeof(s_task));
  task->next=taskctx->firsttask;
  taskctx->firsttask=task;
  task->refcnt=1;

  task->name=NULL;                    /* Initialize the task */
  task->duration=0;
  task->aflag=task->duedate=0;
  return task;
 }
}

The task deletion function frees the space used by a task and removes the task from the list of tasks held by the module context if no reference to the task is left. Otherwise, it decreases the reference counter. If the task is not found in the list we display an error message using the Native Interface function dispmsg. For any output produced by modules, this way of printing should always be preferred to the corresponding C printing functions.

static void task_delete(XPRMcontext ctx, void *libctx, void *todel,
                        int typnum)
{
 s_taskctx *taskctx;
 s_task *task,*prev;

 if((todel!=NULL)&&((--((s_task *)todel)->refcnt)<1))
 {
  taskctx=libctx;
  task=todel;
  if(taskctx->firsttask==task) taskctx->firsttask=task->next;
  else
  {
   prev=taskctx->firsttask;
   while((prev->next!=NULL) && (prev->next!=task))
    prev=prev->next;
   if(prev->next==NULL) mm->dispmsg(ctx, "Task: task not found.\n");
   else prev->next=task->next;
  }
  free(task);
 }
}

The definition of a type instance deletion function does not replace the memory deallocation in the reset service function (see Section Service function reset).

Conversion to and from string

To be able to use initializations blocks with the new type task we define two functions for transforming the task into a string and initializing it from a string. The writing function is also used by the write and writeln procedures for printing this type. The reading function also gets applied by default when the type instance creation function is given a string, but in this example we have defined that the string is interpreted only as the task name.
The format of the string will obviously depend on the type. In this example we have chosen a very simple string format for tasks: the data entries separated by blanks in the order name, duration, flag, due date. The following function prints a task:

static int task_tostr(XPRMcontext ctx, void *libctx, void *toprt, char *str,
                      int len, int typnum)
{
 s_task *task;

 if(toprt==NULL)
  return 0;
 else
 {
  task=toprt;
  return snprintf(str, len, "%s %g %d %d", task->name, task->duration,
                  task->aflag, task->duedate);
 }
}

The next function reads in a task from a string (the flag and due date values may have been omitted):

static int task_fromstr(XPRMcontext ctx, void *libctx, void *toinit,
                        const char *str, int typnum, const char **endp)
{
 double dur;
 int af,due,res,cnt;
 char *name;
 s_taskctx *taskctx;
 s_task *task;

 taskctx=libctx;
 name=alloca(TASK_MAXNAME*sizeof(char));
 af=due=cnt=0;
 res=sscanf(str,"%s %lf %d%n %d%n",name,&dur,&af,&cnt,&due,&cnt);
 if(res<3)
 {
  if(endp!=NULL) *endp=str;
  return XPRM_RT_ERROR;
 }
 else
 {
  task=toinit;
  task->name=mm->regstring(ctx, name);
  task->duration=dur;
  task->aflag=(res>=3)?af:0;
  task->duedate=(res==4)?due:0;
  if(endp!=NULL) *endp=str+cnt;
  return XPRM_RT_OK;
 }
}

The Native Interface function regstring that is used here adds the name string to the names dictionary. Any string that is returned to Mosel must be registered this way.

The copy function

Certain assignments in Mosel (assignments that are not stated explicitly, such as array initialization) use the type copy function. If no copy function is defined for a type, the operations where it is necessary are disabled by the compiler for the corresponding type.

For copying the type task we may define the following function where the task toinit becomes a copy of the task src:

static int task_copy(XPRMcontext ctx, void *libctx, void *toinit, void *src,
                     int typnum)
{
 s_task *task1,*task2;

 task1=(s_task *)toinit;
 if(src==NULL)
 {
  task1->name=NULL;
  task1->duration=0;
  task1->aflag=task1->duedate=0;
 }
 else
 {
  task2=(s_task *)src;
  task1->name=task2->name;
  task1->aflag=task2->aflag;
  task1->duedate=task2->duedate;
  task1->duration=task2->duration;
 }
 return 0;
}

The compare function

The compare function is required for the comparison of aggregate objects (for example, a record that contains a field of type 'task'). If no compare function is defined for a type, the operations where it is necessary are disabled by the compiler for the corresponding type.

The following function compares two objects t1 and t2 of type task by comparing all the fields of the two structures. For the comparison of the names it suffices to compare the pointers because we are using the names dictionary of Mosel: it guarantees the uniqueness of the name strings.

static int task_compare(XPRMcontext ctx, void *libctx, void *t1, void *t2, int typnum)
{
 int b;

 if(t1!=NULL)
 {
  if(t2!=NULL)
   b=((((s_task *)t1)->name==((s_task *)t2)->name)  /* This is correct since we
                                               are using Mosel's dictionary */
   &&(((s_task *)t1)->duration==((s_task *)t2)->duration)
   &&(((s_task *)t1)->aflag==((s_task *)t2)->aflag)
   &&(((s_task *)t1)->duedate==((s_task *)t2)->duedate));
  else
   b=0;
 }
 else
  b=(t2==NULL);

 switch(XPRM_COMPARE(typnum))
 {
  case MM_COMPARE_EQ:
    return b;
  case MM_COMPARE_NEQ:
    return !b;
  default:
    return XPRM_COMPARE_ERROR;
 }
}

© 2001-2022 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.