/*****************************************************************************
    Name: asesmp.c                                   

    Description:    ASE API C sample application

    Author: Volodya Sirotinin
            Autodesk, Inc.
            Moscow, Russia.

   Copyright (C) 1992, 1993, 1994 by Autodesk, Inc.
 
   Permission to use, copy, modify, and distribute this software in 
   object code form for any purpose and without fee is hereby granted, 
   provided that the above copyright notice appears in all copies and 
   that both that copyright notice and the limited warranty and 
   restricted rights notice below appear in all supporting 
   documentation.
 
   AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
   AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
   DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
   UNINTERRUPTED OR ERROR FREE.
 
   Use, duplication, or disclosure by the U.S. Government is subject to 
   restrictions set forth in FAR 52.227-19 (Commercial Computer 
   Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
   (Rights in Technical Data and Computer Software), as applicable.

    Entry Points:

    Modification History:
    June 15 1994 - volodyas - original written

    Bugs and restriction on use:

    Notes:

*****************************************************************************/
#ifndef ASE_ASESMP_C
#define ASE_ASESMP_C asesmpc

/****************************************************************************/
/* INCLUDES */
/****************************************************************************/
#include <adslib.h>
#include <string.h>
#include <stdio.h>
#include <asiappl.h>
#include <ase.h>
#include <malloc.h>

/****************************************************************************/
/* TYPEDEFS */
/****************************************************************************/

/****************************************************************************/
/* DEFINES */
/****************************************************************************/
#define BUFLEN           128           /* The local buffer length */
#define STMSIZE          BUFLEN*4      /* The SQL statement buffer size */
#define DEFSTMSIZE BUFLEN              /* default size of statement */
#define DEFSTMINC  BUFLEN              /* value for increment block size */
#define MAXSTMSIZE (BUFLEN*64)         /* maximum statement size */
#define FREE_TOKENBUF    ((void*)(-1)) /* Pointer value for ase_addtoken() */
                                       /* free static buffer */
#define NEW_TOKENBUF     NULL          /* Pointer value for ase_addtoken(),*/

/****************************************************************************/
/* LOCAL FUNCTIONS */
/****************************************************************************/

/* Command processing functions */
static int asesmp_do() ;
static int asesmp_lpn() ;
static int asesmp_sel() ;
static int asesmp_stat() ;
static int asesmp_row() ;
static int asesmp_link() ; 
static int asesmp_err() ; 

/* Link Paths manipulation */
static EAsiBoolean lp_view(ASE_LPDSC lp) ;
static EAsiBoolean lp_erase(ASE_LPDSC lp) ;
static EAsiBoolean lp_new(ASE_LPDSC lp) ;
static EAsiBoolean lp_rename(ASE_LPDSC lp) ; 
static char       *lp_getName(ASE_LPDSC lp, char *pPrompt) ;
static ASE_LPDSC   lp_getDOR(char *pPrompt, 
                             EAsiBoolean needConnect, 
                             EAsiBoolean needAseConnect) ;
static EAsiBoolean lp_getTabCols(ASE_LPDSC lp, 
                              ASICOLDSC *pPack[], 
                              int *pColQty) ;
static EAsiBoolean lp_getRow(ASE_LPDSC lp,
                             ASICOLDSC *pKey, int pKeyColQty,
                             ASICOLDSC **pRow, int *pColQty) ;
static void        lp_print(ASE_LPDSC lp) ;
static void        lp_printPath(ASE_LPDSC lp) ;
static void        lp_printStat(ASE_LPDSC lp) ;

/* Cursor manipulations */
static EAsiBoolean csr_scroll(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean csr_viewLinks(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean csr_eraseLinks(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean csr_makeLink(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean csr_reloadDA(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean csr_getVals(ASICURSOR csr, 
                               ASICOLDSC *pVals[],
                               int *pColQty) ;
static ASE_LSDSC   csr_getLinks(ASICURSOR csr,
                                ASE_LPDSC lp) ;
static void        csr_printRow(ASICURSOR csr) ;

/* Link Selection manipulation */
static EAsiBoolean ls_scan(ASE_LSDSC ls) ;
static ASE_LSDSC   ls_create() ;
static EAsiBoolean ls_filter(ASE_LSDSC ls) ;
static void        ls_print(ASE_LSDSC ls,
                            ASE_LPDSC lp,
                            ASICOLDSC KeyBuf[],
                            int ColQty) ;
static void        ls_printLp(ASE_LSDSC ls, 
                              const char *pName,
                              ASICOLDSC KeyBuf[],
                              int ColQty) ;
static void        ls_printStat(ASE_LSDSC ls, ASE_LPDSC lp) ;
static void        ls_printTypeStat(ASE_LSDSC ls, 
                                  ASE_LPDSC lp,
                                  char *pName,
                                  char *pXName,
                                  EAseLinkType Type) ;
static void        ls_printLPNsStat(ASE_LSDSC ls) ;
static void        ls_printXsStat(ASE_LSDSC ls) ;

/* Link Manipulations */
static EAsiBoolean link_edit(ASE_LINKDSC link, 
                            ASE_LPDSC lp, 
                            ASICOLDSC Key[], 
                            int ColQty) ;
static EAsiBoolean link_entMake(ASICURSOR csr, ASE_LPDSC lp) ;
static EAsiBoolean link_daMake(ASICURSOR csr, ASE_LPDSC lp) ;
static void        link_print(ASE_LINKDSC link, ASICOLDSC Key[], int ColQty) ;

/* Packet manipulations */
static void        pack_print(ASICOLDSC Pack[], int ColQty) ;
static void        pack_printCols(ASICOLDSC Pack[], int ColQty) ;
static void        pack_printVals(ASICOLDSC Pack[], int ColQty) ;
static EAsiBoolean pack_edit(ASICOLDSC Pack[], int ColQty) ;
static EAsiBoolean pack_getCols(ASICOLDSC ColList[], int ColQty, 
                               ASICOLDSC *pCols[], int *pColQty) ;

/* Sessions management */
static EAsiBoolean connect(ASE_LPDSC lp) ;
static EAsiBoolean connectAse(ASE_LPDSC lp) ;
static ASISESSION  getSession() ;
static EAsiBoolean isConnected(ASE_LPDSC lp) ;
static void        disconnect() ;

/* Error printing */
static void        printAseErr(ASE_DSC dsc) ;   
static void        printAsiErr(ASIHANDLE handle) ;

/* Utilities */
static EAsiBoolean testDsc(ASE_DSC dsc) ;
static void        printColDsc(ASICOLDSC col) ;
static void        printBufNames(const struct resbuf *pBuf) ;
static void        pauseInput(const char* pPrompt) ;
static int         callCmd(char *pCmdName, struct resbuf *pParms) ;
static char       *addtoken(char *newtoken) ;

/* Initializing/terminating of APIs */
static EAsiBoolean smpinit() ;
static void        smpterm() ;
static EAsiBoolean isInit() ;

/* ADS Utility functions */
static int loadfunc () ;
static int unloadfunc () ;
static int execfunc () ;

typedef struct {
    char *cmdname;
    int (*cmdfunc)();
} CMDADS;                              /* Typedef for command definition */

/****************************************************************************/
/* GLOBAL VARIABLES */
/****************************************************************************/

static CMDADS cmd[] =  {
                       {"C:ASESMPDO",  asesmp_do},
                       {"C:ASESMPLPN", asesmp_lpn},
                       {"C:ASESMPSEL", asesmp_sel},
                       {"C:ASESMPSTAT", asesmp_stat},
                       {"C:ASESMPROW", asesmp_row},
                       {"C:ASESMPLINK", asesmp_link},
                       {"C:ASESMPERR", asesmp_err}
                      };

ASE_APPLDSC AseAppl=ASE_DSC_NULL ;  /* The global ASE application desc */
ASE_LPDSC   AseEnv=ASE_DSC_NULL ;   /* The global ENvironment reference desc */
ASIENV      AsiAppl=0L ;            /* The global ASI application desc */
ASISESSION  AsiSes=0L ;             /* The global ASI session desc */   
/****************************************************************************/
/* FUNCTIONS */
/****************************************************************************/

/****************************************************************************/
/*.doc asesmp_do (internal) */
/*+
ASESMPDO     - Database Object Reference statistic
               This command demostrates how to get the
               information by the given Database Object Reference.
Command: ASESMPDO        
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_do() 
{
    ASE_LPDSC lp ;                     /* The DOR descriptor */
    struct resbuf *pBuf ;              /* For subordinate DO paths */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Get the Database Object Reference */
        if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiTrue)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Test the DO */
        if ( testDsc(lp) != kAsiGood ) {
            break ;
        }
          /* Print the DO path attributes */
        lp_printPath(lp) ;
          /* Print the existing subordinate DO paths */
          /* for Database Object reference */
        if ( ase_lp_getPathCode(lp) != kAseTableCode &&
             ase_lp_getPathCode(lp) != kAseLpnCode ) {
            if ( (pBuf = ase_lp_getPaths(lp, 
                       ASE_DO_EXIST|ASE_DO_UNKNOWN)) 
                       != NULL ) {
                pauseInput("\nPress key for printing subordinate DOs") ;
                printBufNames(pBuf) ;
                ads_relrb(pBuf) ;
            } else {
                ads_printf("\nNo subordinate existing DOs") ;
                printAseErr(lp) ;
            }
        }
        pauseInput("\nPress any key for the related link information...") ;
          /* Print the DO related information */
        lp_printStat(lp) ;
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&lp) ;
    return retCode ;
} /* end of asesmp_do() */

/****************************************************************************/
/*.doc asesmp_lpn(internal) */
/*+
ASESMPLPN    - Creating, Erasing, Renaming of LPN(s)
               This command  demonstrates how to create, erase, rename,
               and get the structure of the LPN(s).
Command: ASESMPLPN
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_lpn() 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;        /* Link Path descriptor */
    char buf[BUFLEN] ;               /* The buffer for entering */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    int retword ;                      /* ads_getkword() returning value */

    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Ask for the DO entering */
        if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
            break ;
        }
              /* Loop for the asking LPN options */
        do {
              /* Erase/Rename/Create/View/<eXit> */
            if ( ads_initget(0, "E R C V X") != RTNORM ) {
                break ;
            }
            retword=ads_getkword(
                       "\nErase/Rename/Create/View/<eXit>:", 
                       buf);

            if ( retword != RTNORM && retword != RTNONE ) {
                break ;
            }
            if ( retword == RTNONE || buf[0] == '\0' || buf[0] == 'X' ) {
                retCode = kAsiGood ;
                break ;
            }
            switch(buf[0]) {
            case 'E':                  /* ERASE */ 
                retCode = lp_erase(lp) ;
                break ;
            case 'R':                  /* RENAME */
                retCode = lp_rename(lp) ;
                break ;
            case 'C':                  /* CREATE */
                retCode = lp_new(lp) ;
                break ;
            case 'V':                  /* VIEW */
                retCode = lp_view(lp) ;
                break ;
            }
        } while(0) ;
    } while(0) ;
    ase_dsc_free(&lp) ;
    return retCode ;
} /* end of asesmp_lpn() */

/****************************************************************************/
/*.doc asesmp_stat(internal) */
/*+
ASESMPSTAT   - Links Statistic
               This command demonstrates how to get the link information
               for the selected drawing objects.
Command: ASESMPSTAT
  per each Xref/Block
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_stat() 
{
    ASE_LSDSC ls=ASE_DSC_NULL ;   /* Link selection desc */
    ads_name ssname ;                  /* Entity selection set name */
    ASE_LPDSC lp=ASE_DSC_NULL ;     /* The DOR descriptor */
    long slen ;                     /* Selection set length */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */

    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Allocate the Link Selection Descriptor */
        if ( (ls=ase_dsc_alloc(AseAppl, kAseApiLinkSel)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate Link Selection descriptor") ;
            break ;
        }
          /* Ask for the entities selection */
          /* Check the selection length */
        if ( ads_ssget(NULL, NULL, NULL, NULL, ssname) != RTNORM ||
             ads_sslength(ssname, &slen) != RTNORM ||
             slen <= 0L ) {
            ads_printf("\nWrong entity selection") ;
            break ;
        }
          /* Init the link selection by the selected entities */
        if ( ase_ls_initSel(ls, ssname) != kAsiGood ) {
            if ( ase_dsc_errDsc(ls, 0) != eAseEDscApi ||
                 ase_dsc_errCode(ls, 0) != eAseApiErrSelEmpty ) {
                ads_printf("\nLink Selection creating problem") ;
                printAseErr(ls) ;
            } else {
                  /* No related links */
                ads_printf("\nNo Links are specified") ;
                retCode = kAsiGood ;
            }
            break ;
        }
          /* Test the Link Selection */
        if ( testDsc(ls) != kAsiGood ) {
            break ;
        }
          /* Get the Database Object Reference */
        if ( (lp=lp_getDOR(
        "\nEnter the registered DOR or <.> for empty one:", 
             kAsiFalse,
             kAsiFalse)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Test, whether the Database Object Reference is registered */
        if ( ! (ase_lp_getStatus(lp) & ASE_DO_REG) ) {
            ads_printf("\nThe DOR isn't registered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Print Link Selection statistic */
        ls_printStat(ls, lp) ;
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&ls) ;
    ase_dsc_free(&lp) ;
    return retCode ;
} /* end of asesmp_stat() */

/****************************************************************************/
/*.doc asesmp_sel(internal) */
/*+
ASESMPSEL    - Links Selection manipulations
               This command demonstrates how to manipulate with the
               Link Selections.
Command: ASESMPSEL
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_sel() 
{
    ASE_LSDSC lsCurrent=ASE_DSC_NULL ;   /* The current Link Selection */
    ASE_LSDSC lsNew=ASE_DSC_NULL ;       /* The second Link Selection */
    char buf[BUFLEN] ;               /* The buffer for entering */
    int retword ;                      /* ads_getkword() returning value */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */

    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Create the current link selection */
        if ( (lsCurrent=ls_create()) == ASE_DSC_NULL ) {
            break ;
        }
          /* Loop for Link Selection processing */
        do {
              /* Print the links quantity in current selection */
            ads_printf("\nSelected links #%ld", ase_ls_getQty(lsCurrent)) ;
              /* Print/Unite/Intersect/Subtract/Filter/<eXit> */
            if ( ads_initget(0, "P U I S F X") != RTNORM ) {
                break ;
            }
              /* Ask for the entering */
            retword=ads_getkword(
                      "\nPrint/Unite/Intersect/Subtract/Filter/<eXit>:",
                      buf);
            if ( retword != RTNORM && retword != RTNONE ) {
                break ;
            }
            retCode = kAsiGood ;
            if ( retword == RTNONE || buf[0] == '\0' || buf[0] == 'X' ) {
                break ;
            }
            switch(buf[0]) {
            case 'P':                  /* PRINT */
                ls_print(lsCurrent, 
                             ASE_DSC_NULL,
                             (ASICOLDSC*)NULL, 
                             0) ;
                break ;
            case 'U':                  /* UNITE */ 
                  /* Ask for the new Link Selection */
                if ( (lsNew=ls_create()) == ASE_DSC_NULL ) {
                    break ;
                }
                  /* Unite the link selections */
                retCode = ase_ls_unite(lsCurrent, lsNew) ;
                break ;
            case 'I':                  /* INTERSECT */
                  /* Ask for the new Link Selection */
                if ( (lsNew=ls_create()) == ASE_DSC_NULL ) {
                    break ;
                }
                  /* Intersect the link selections */
                retCode = ase_ls_intersect(lsCurrent, lsNew) ;
                break ;
            case 'S':                  /* SUBTRACT */
                  /* Ask for the new Link Selection */
                if ( (lsNew=ls_create()) == ASE_DSC_NULL ) {
                    break ;
                }
                  /* Subtract the link selections */
                retCode = ase_ls_subtract(lsCurrent, lsNew) ;
                break ;
            case 'F':                  /* FILTER */
                retCode = ls_filter(lsCurrent) ;
                break ;
            }
              /* Free the Link Selection */
            ase_dsc_free(&lsNew) ;
            if ( retCode != kAsiGood ) {
                break ;
            }
        } while(1) ;
    } while(0) ;
    ase_dsc_free(&lsCurrent) ;
    return retCode ;
} /* end of asesmp_sel() */

/****************************************************************************/
/*.doc asesmp_row(internal) */
/*+
ASESMPROW    - This command demonstrates how to get, create and view links
               for the given table row.
Command: ASESMPROW
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_row() 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;     /* The DOR descriptor */
    ASICURSOR csr=0L ;              /* The cursor descriptor */
    ASISTATEMENT stm=0L ;           /* The statement desc */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    char stmstrbuf[STMSIZE] ;      /* The buffer length */
    char buf[BUFLEN] ;            /* The buffer */

    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Get the Database Object Reference */
        if ( (lp=lp_getDOR("\nEnter the Table Reference:",
                        kAsiTrue,
                        kAsiFalse)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Test, whether it is the Table Reference */
        if ( ase_lp_getPathCode(lp) != kAseTableCode &&
             ase_lp_getPathCode(lp) != kAseLpnCode ) {
            ads_printf("\nNot the Table Reference was entered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Create statement descriptor */
        if ( asi_constr_stm (&stm) != kAsiGood ) {
            ads_printf("\nCan't construct ASI statement") ;
        }
          /* Get the SQL path to the table */
        if ( ase_lp_getName(lp, buf, BUFLEN, kAseSQLCode) != kAsiGood ) {
            ads_printf("\nCan't get the SQL table name") ;
            printAseErr(lp) ;
            break ;
        }
          /* Get the statement string */
        sprintf(stmstrbuf, "SELECT * FROM %s", buf) ;
          /* Prepare the statement */
        if ( asi_prepare (stm, 
                          getSession(),  
                          stmstrbuf) != kAsiGood ) {
            ads_printf("\nCan't prepare the statement \n[%s]", stmstrbuf) ;
            printAsiErr(stm) ;
            break ;
        }
        if ( asi_constr_csr(&csr) != kAsiGood ) {
            ads_printf("\nCan't construct the cursor") ;
            printAsiErr(csr) ;
            break ;
        }
        if ( asi_alloc_csr(csr, stm, "XXX", 
                           kAsiScroll, kAsiSnsUndef) != kAsiGood ) {
            ads_printf("\nCan't allocate the cursor") ;
            printAsiErr(csr) ;
            break ;
        }                   
        if ( asi_open(csr) != kAsiGood ) {
            ads_printf("\nCan't open the cursor") ;
            printAsiErr(csr) ;
            break ;
        }   
        if ( csr_scroll(csr, lp) == kAsiGood ) {
            retCode = kAsiGood ;
        }
    } while(0) ;
    if ( csr != 0L ) {
          /* Close the cursor */
        asi_close(csr) ;
          /* Destroy the cursir descriptor */
        asi_destroy_csr(&csr) ;
    }
    if ( stm != 0L ) {
          /* Deallocate the statement desc */
        asi_dealloc_stm (stm);
          /* Free the statement dsc */
        asi_destroy_stm(&stm) ;
    }
    return retCode ;
} /* end of asesmp_row() */

/****************************************************************************/
/*.doc asesmp_link(internal) */
/*+
ASESMPLINK   - This command demonstrates how to manipulate with the
               links.
Command:ASESMPLINK
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_link() 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;        /* The Link Path descriptor */
    ASE_LSDSC ls=ASE_DSC_NULL ;        /* The Link Selection descriptor */
    ads_name ename ;                   /* The entity name */
    ads_point pt ;                         /* the point */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
          /* Get the DOR */
        if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Check, whether it is registered */
        if ( !(ase_lp_getStatus(lp) & ASE_DO_REG) ) {
              /* The DO isn't registsred */
            ads_printf("\nDOR isn't registered") ;
            break ;
        }
        /* Ask for the entity name */
        if ( ads_entsel("\nSelect object:", ename, pt) != RTNORM ) {
            ads_printf("\nWrong entity name input") ;
            break ;
        }
        /* Allocate the Link Sel */
        if ( (ls=ase_dsc_alloc(AseAppl, kAseApiLinkSel)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Selection descriptor") ;
            break ;
        }
          /* Create the link selection for the Entity */
        if ( ase_ls_initEnt(ls, ename) != kAsiGood ) {
            if ( ase_dsc_errDsc(ls, 0) != eAseEDscApi ||
                 ase_dsc_errCode(ls, 0) != eAseApiErrSelEmpty ) {
                ads_printf("\nLink Selection creating problem") ;
                printAseErr(ls) ;
            } else {
                  /* No related links */
                ads_printf("\nNo Links are specified") ;
                retCode = kAsiGood ;
            }
            break ;
        }
          /* Check the Link Selection length */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nWrong Link Selection") ;
            printAseErr(ls) ;
            break ;
        }
          /* Filter the links to the specified DOR */
        if ( ase_ls_intersectLpDsc(ls, lp) != kAsiGood ) {
            ads_printf("\nLink Selection intersecting problem") ;
            printAseErr(ls) ;
            break ;
        }
          /* Check the resulting Link Selection length */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nNo Links to the specified DOR") ;
            break ;
        }
          /* Process the links */
        retCode = ls_scan(ls) ;
    } while(0) ;
    ase_dsc_free(&ls) ;
    ase_dsc_free(&lp) ;
    return retCode ;
} /* end of asesmp_link() */

/****************************************************************************/
/*.doc asesmp_err(internal) */
/*+
ASESMPERR    - Global Error          
               This command prints the last ASE global error data.
Command:ASESMPERR
-*/
/****************************************************************************/
static int 
/*FCN*/asesmp_err() 
{
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    do {
          /* Check, whether appls were initialized */
        if ( ! isInit() ) 
            break ;
        if ( ase_appl_getAseErr(AseAppl) != kAsiGood ) {
            ads_printf("\nCan't get the global ASE error") ;      
        } else {
            ads_printf("\nThe Global ASE error data are:") ;
            retCode = kAsiGood ;
        }
        printAseErr(AseAppl) ;
    } while(0) ;
    return retCode ;
} /* end of asesmp_err() */

/****************************************************************************/
/*.doc lp_view(internal) */
/*+
  This function prints the structure of the Link Path Key for the
  Table Reference. 
-*/
/****************************************************************************/
static EAsiBoolean
/*FCN*/lp_view(ASE_LPDSC lp) 
{
    char *pLPN=NULL ;                  /* LPN buffer */
    EAsiBoolean retCode=kAsiBad ;      /* The returning code */

    do {
          /* Get the LPN */
        if ( (pLPN=lp_getName(lp, "\nEnter existing LPN or <?> LPNs list:")) == NULL ) {
            break ;
        }
          /* Check it */
        if ( ase_lp_initName(lp, pLPN) != kAsiGood ) {
            ads_printf("\nWrong LPN was entered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Print the Key Description */
        lp_print(lp) ;
        retCode = kAsiGood ;
    } while(0) ;
    if ( pLPN != NULL ) {
        free (pLPN) ;
    }
    return retCode ;
} /* end of lp_view() */

/****************************************************************************/
/*.doc lp_erase(internal) */
/*+
  This function erases all of the Link Paths related with the
  Database Object Reference
-*/
/****************************************************************************/
static EAsiBoolean
/*FCN*/lp_erase(ASE_LPDSC lp) 
{
    EAsiBoolean retCode =kAsiBad ;    /* The returning code */
    do {
          /* Test, whether it is registered */
        if ( ! (ase_lp_getStatus(lp) & ASE_DO_REG) ) {
            ads_printf("\nThe DOR isn't registered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Test, whether DOR's links are updatable */
        if ( ase_lp_isUpdatable(lp) != kAsiTrue ) {
            ads_printf("\nThe related link information can't be updatable") ;
            printAseErr(lp) ;
            break ;
        }
          /* Do erase of the Link Path registration */
          /* and all the related links */
        if ( ase_lp_erase(lp)  != kAsiGood ) {
            ads_printf("\nCan't erase the related link information") ;
            printAseErr(lp) ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    return retCode ;
} /* end of lp_erase() */

/****************************************************************************/
/*.doc lp_new(internal) */
/*+
  This function creates the new Link Path Name.
-*/
/****************************************************************************/
static EAsiBoolean
/*FCN*/lp_new(ASE_LPDSC lp) 
{
    ASICOLDSC *pTabCols=NULL ;          /* The Table Column Descriptors */
    ASICOLDSC *pKey=NULL ;              /* The Key Column Descriptors */
    char *pLPN=NULL ;                   /* new LPN buffer */
    int TabColQty=0 ;                   /* The table column quantity */
    int ColQty=0 ;                      /* The key column quantity */
    EAsiBoolean retCode=kAsiBad ;       /* The returning code */

    do {
          /* Check whether or not Env is connected */
          /* and connect in application */
        if ( connect(lp) != kAsiGood ||
             isConnected(lp) != kAsiTrue ) {
            break ;
        }
          /* Ask for the new LPN */
        if ( (pLPN=lp_getName(lp, "\nEnter the new LPN:")) == NULL ) {
            break ;
        }
          /* Set the new LPN */
        if ( ase_lp_setName(lp, pLPN, kAseLpnCode) != kAsiGood ) {
            ads_printf("\nWrong LPN was entered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Get the column description */
        if ( lp_getTabCols(lp, &pTabCols, &TabColQty) != kAsiGood ) {
           break ;
        }
          /* Ask for the key columns desc */
        if ( pack_getCols(pTabCols, TabColQty, &pKey, &ColQty) != kAsiGood ) {
            ads_printf("\nNo Key Columns") ;
            break ;
        }
          /* Do the LPN creating */
        if ( ase_lp_create(lp, pKey, ColQty) != kAsiGood ) {
            ads_printf("\nCan't create LPN") ;
            printAseErr(lp) ;
            break ;
        }
          /* Make that LPN as the current for ASE */
        if ( ase_lp_setCurrent(lp) != kAsiGood ) {
            ads_printf("\nCan't set the LPN as the current for ASE") ;
            printAseErr(lp) ;
        }
        retCode = kAsiGood ;
    } while(0) ;
      /* Free the allocated column descriptors */
    asei_destroy_cdscpack(&pKey, ColQty) ;
      /* Free the allocated column descriptors */
    asei_destroy_cdscpack(&pTabCols, TabColQty) ;
    if ( pLPN != NULL ) {
        free (pLPN) ;
    }
    return retCode ;
} /* end of lp_new() */

/****************************************************************************/
/*.doc lp_rename(internal) */
/*+
  This function renames the Link Path in accordance with the
  LPN that is asked.
-*/
/****************************************************************************/
static EAsiBoolean
/*FCN*/lp_rename(ASE_LPDSC lp) 
{
    char *pLPN=NULL ;                  /* LPN buffer */
    char buf[BUFLEN] ;                 /* The buffer for existing LPN */
    EAsiBoolean retCode=kAsiBad ;      /* The returning code */

    do {
          /* Check the LPN existance */
        if ( ase_lp_getPathCode(lp) != kAseLpnCode ||
             ase_lp_getName(lp, buf, BUFLEN, kAseLpnCode) != kAsiGood ) {
            ads_printf("\nLPN isn't set") ;
            break ;
        }
          /* Print the existing LPN */
        ads_printf("\nOld LPN: %s", buf) ;
          /* Ask for the new LPN */
        if ( (pLPN=lp_getName(lp,"\nEnter the new LPN:")) == NULL ) {
            break ;
        }
          /* Do rename of the Link Path and */
          /* all the related links */
        if ( ase_lp_rename(lp, pLPN) != kAsiGood ) {
            ads_printf("\nCan't rename the LPN") ;
            printAseErr(lp) ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( pLPN != NULL ) {
        free (pLPN) ;
    }
    return retCode ;
} /* end of lp_rename() */
 
/****************************************************************************/
/*.doc lp_getName(internal) */
/*+
  This function asks for the LPN entering.
  The entering of <?> causes the printing of the list with the
  all existing LPNs, related with the specified Database Object Reference.
  If the lp == ASE_DSC_NULL, then all the existing LPNs
  are printed.
  Prints the default prompt if pPrompt is NULL.
  Returns the pointer to the allocated LPN in success, 
  NULL otherwise. The space allocated by retruning pointer should
  be released with the aid of free() function.
-*/
/****************************************************************************/
static char*
/*FCN*/lp_getName(ASE_LPDSC lp, char *pPrompt) 
{
    ASE_LPDSC lpbuf=ASE_DSC_NULL ;     /* The DOR descriptor */
    struct resbuf *pBuf ;              /* LPNs list pointer */ 
    char buf[BUFLEN] ;               /* The buffer for LPN entering */
    char *pRetPtr=NULL ;               /* The returning LPN name buffer */


    if ( pPrompt == NULL ) {
        pPrompt = "\nEnter LPN or <?> for LPNs list:" ;
    }
    do {
        if ( lp == ASE_DSC_NULL ) {
              /* Allocate the descriptor */
            if ( (lpbuf=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) == ASE_DSC_NULL ) {
                ads_abort("\nCan't allocate Link Path descriptor") ;
                break ;
            }
        } else {
            lpbuf = ase_dsc_clone(lp) ;
        }
        do {
              /* Ask for the LPN entering */
            if ( ads_getstring(0, pPrompt, buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
            if ( buf[0] == '?' ) {
                  /* Fast check, wheter at least one LPN exist */
                if ( ! (ase_lp_getStatus(lpbuf) & ASE_DO_REG) ) {
                    ads_printf("\nNo Link Information exist in drawing") ;
                    printAseErr(lpbuf) ;
                    continue ;
                }
                  /* Print the list of the LPNs,  */
                  /* related with the Databaser Object Reference */
                if ( (pBuf=ase_lp_getLinkNames(lpbuf)) == NULL ) {
                    ads_printf("\nNo LPNs are available") ;
                    printAseErr(lpbuf) ;
                    continue ;
                } else {
                    printBufNames(pBuf) ;
                    ads_relrb(pBuf) ;
                }
                continue ;
            } else {
                if ( (pRetPtr=(char*)calloc(1, strlen(buf)+1)) == NULL ) {
                    ads_abort("\nNo Memory") ;
                    break ;
                }
                strcpy(pRetPtr, buf) ;
                break ;
            }
        } while (1) ;
    } while(0) ;
    ase_dsc_free(&lpbuf) ;
    return pRetPtr ;
} /* end of lp_getName() */

/****************************************************************************/
/*.doc lp_getDOR(internal) */
/*+
  This function prints the current setting and asks for 
  accepting of it or for the entering an another one.
  Prints the default prompt if pPrompt is NULL.
  Connects to the specified Environment if the
  needConnect argument equals to kAsiTrue.
  Connects ASE to the specified environment is the
  needAseConnect equals to kAsiTrue.
  Returns the descriptor of the resulting link path.
-*/
/****************************************************************************/
static ASE_LPDSC   
/*FCN*/lp_getDOR(char *pPrompt, 
              EAsiBoolean needConnect, 
              EAsiBoolean needAseConnect) 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;       /* The DOR descriptor */
    char buf[BUFLEN] ;              /* The buffer for DO path */
    EAsiBoolean retCode=kAsiBad ;     /* The exit condition code */ 

    if ( pPrompt == NULL ) {
        pPrompt = "\nEnter DOR or <.> for empty one:" ;
    }
    do {
          /* Allocate the descriptor */
        if ( (lp=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate Link Path descriptor") ;
            break ;
        }
          /* Get the current settings */
        if ( ase_lp_initCurrent(lp) != kAsiGood ) {
            ads_printf("\nCan't get the current ASE settings") ;
            printAseErr(lp) ;
            break ;
        } else {
            ase_lp_getName(lp, buf, BUFLEN, kAsePathCode) ;
              /* Print the current settings */
            ads_printf("\nCurrent Settings [%s]", buf) ;
        }
          /* Ask for the DO path entering */
        if ( ads_getstring(0, pPrompt, buf) != RTNORM ) {
            ads_printf("\nNo input") ;
            ase_dsc_free(&lp) ;
            break ;
        }
        if ( buf[0] != '\0' ) {
              /* Correct an empty path */
            if ( buf[0] == '.' ) {
                buf[0] = '\0' ;
            }
              /* Compare with the current settings */
              /* to still use the already initialized */
              /* Link Path descriptor */
            if ( ! ase_lp_cmpName(lp, buf, kAsePathCode) ) {
                  /* Initialize the descriptor */
                if ( ase_lp_initPath(lp, buf) != kAsiGood ) {
                    ads_printf("\nThe wrong DOR was entered") ;
                    printAseErr(lp) ;
                    break ;
                }
            }
        }
          /* Connect application to the Environment */
        if ( needConnect == kAsiTrue ) {
            if ( connect(lp) != kAsiGood ) {
                break ;
            }
        }
          /* Connect ASE to the Environment */
        if ( needAseConnect == kAsiTrue ) {
            if ( connectAse(lp) != kAsiGood ) {
                break ;
            }
        }
          /* Make the Database Object Reference as the current for ASE */
        if ( ase_lp_setCurrent(lp) != kAsiGood ) {
            ads_printf("\nCan't set the DOR as the current for ASE") ;
            printAseErr(lp) ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( retCode != kAsiGood ) {
        ase_dsc_free(&lp) ;
    }
    return lp ;
} /* end of lp_getDOR() */

/****************************************************************************/
/*.doc lp_getTabCols(internal) */
/*+
  Gets the description of the table columns
  Returns kAsiBad if something is wrong.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/lp_getTabCols(ASE_LPDSC lp, 
                     ASICOLDSC *pPack[], 
                     int *pColQty) 
{
    ASISTATEMENT stm=0L ;            /* The statement desc */
    ASICOLDSC col;                   /* column description */
    int colcount ;                   /* The table columns quatity */
    int index ;                      /* The scanning index */
    char buf[BUFLEN] ;               /* The general buffer */
    char stmstrbuf[STMSIZE] ;         /* char stm str buffer */
    EAsiBoolean retCode=kAsiBad ;    /* The returning code */

    do {
          /* Test, whether it is the Table Reference */
        if ( ase_lp_getPathCode(lp) != kAseTableCode &&
             ase_lp_getPathCode(lp) != kAseLpnCode ) {
            ads_printf("\nNot the Table Reference was entered") ;
            printAseErr(lp) ;
            break ;
        }
          /* Create statement descriptor */
        asi_constr_stm (&stm);
          /* Get the SQL path to the table */
        if ( ase_lp_getName(lp, buf, BUFLEN, kAseSQLCode) != kAsiGood ) {
            ads_printf("\nCan't get the SQL table name") ;
            break ;
        }
          /* Get the statement string */
        sprintf(stmstrbuf, "SELECT * FROM %s", buf) ;
          /* Prepare the statement */
        if ( asi_prepare (stm, 
                          getSession(),  
                          stmstrbuf) != kAsiGood ) {
            ads_printf("\nCan't prepare the statement \n[%s]", stmstrbuf) ;
            break ;
        }
          /* Ask for the columns quantity */
        colcount = asi_colcount(stm) ;
          /* Allocate the packet */
        if ( (*pPack=asei_constr_cdscpack(colcount)) == (ASICOLDSC*)NULL ) {
            ads_abort("\nCan't allocate the columns packet") ;
            break ;
        }
          /* Fill it with the column descrption */
        for ( index = 0, *pColQty = 0 ; 
              index < colcount ; 
              ++index, ++*pColQty ) {
            if ( asi_cds(stm, index, &col) != kAsiGood ) {
                ads_printf("\nCan't get the column description") ;
                break ;
            }
              /* Duplicate it and add to the Key dsc array */
            (*pPack)[index] = asei_dupl_cdsc(col) ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( retCode != kAsiGood ) {
          /* Free the allocated column descriptors */
        asei_destroy_cdscpack(pPack, *pColQty) ;
    }
    if ( stm != 0L ) {
          /* Deallocate the statement desc */
        asi_dealloc_stm (stm);
          /* Free the statement dsc */
        asi_destroy_stm(&stm) ;
    }
    return retCode ;
} /* end of lp_getTabCols() */

/****************************************************************************/
/*.doc lp_getRow(internal) */
/*+
  Gets the values of the row, specified by the key values.
  Puts the values into the pRow packet, which is allocated here.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/lp_getRow(ASE_LPDSC lp,
                 ASICOLDSC *pKey, int KeyColQty,
                 ASICOLDSC **pRow, int *pColQty) 
{
    ASIIDENT ident ;                   /* Column identifier */
    ASISTATEMENT stm=0L ;              /* The statement desc */
    ASICURSOR csr=0L ;                 /* The cursor descriptor */
    char buf[BUFLEN] ;                 /* The general buffer */
    char *pstmbuf ;                    /* statement buffer pointer */
    int index ;                        /* scanning index */
    EAsiBoolean retCode=kAsiBad ;      /* The returning code */

    do {
          /* Check, whether Environment is connected */
        if ( isConnected(lp) != kAsiTrue ) {
            ads_printf("\nEnvironment isn't connected") ;
            break ;
        }
          /* Create statement descriptor */
        if ( asi_constr_stm (&stm) != kAsiGood ) {
            ads_printf("\nCan't construct ASI statement") ;
        }
          /* Get the SQL path to the table */
        if ( ase_lp_getName(lp, buf, BUFLEN, kAseSQLCode) != kAsiGood ) {
            ads_printf("\nCan't get the SQL table name") ;
            printAseErr(lp) ;
            break ;
        }
          /* Allocate the statement buffer */
        if ( (pstmbuf=addtoken(NEW_TOKENBUF)) == NULL ) {
            break ;
        }
        if ( addtoken("SELECT * FROM ") == NULL )
            break ;
          /* Add table name */
        if ( addtoken(buf) == NULL )
            break ;
        if ( addtoken(" WHERE ") == NULL )
            break ;
        for ( index=0 ; index < KeyColQty ; index++ ) {
              /* Add delimiter */
            if ( index ) {
               if ( addtoken(" AND ") == NULL )
                   break ;
            }
              /* Get the column identifier */
            if ( asi_cdsc_name(pKey[index], &ident) != kAsiGood ) {
                ads_printf("\nCan't get the column identifier") ;
            }
              /* Get the ident name */
            if ( asi_get_ident(ident, buf, BUFLEN) == NULL ) {
                ads_printf("\nCan't get the identifier name") ;
                asi_destroy_ident(&ident) ;
                break ;
            }
              /* Destroy the identifier */
            asi_destroy_ident(&ident) ;
              /* Add the column name */
            if ( addtoken(buf) == NULL ) 
                break ;
              /* Add the binding symbol */
            if ( addtoken("=?") == NULL )
                break ;
        }
          /* Check exit condition */
        if ( index < KeyColQty )
            break ;
          /* Prepare the statement */
        if ( asi_prepare (stm, 
                          getSession(),  
                          pstmbuf) != kAsiGood ) {
            ads_printf("\nCan't prepare the statement \n[%s]", pstmbuf) ;
            printAsiErr(stm) ;
            break ;
        }
          /* Construct the cursor */
        if ( asi_constr_csr(&csr) != kAsiGood ) {
            ads_printf("\nCan't construct the cursor") ;
            printAsiErr(csr) ;
            break ;
        }
          /* Allocate the cursor */
        if ( asi_alloc_csr(csr, stm, "XXX", 
                           kAsiScroll, kAsiSnsUndef) != kAsiGood ) {
            ads_printf("\nCan't allocate the cursor") ;
            printAsiErr(csr) ;
            break ;
        }                   
          /* Bind the input variables */
        for ( index = 0 ; index < KeyColQty ; index++ ) {
            if ( asei_bnd(csr, index, pKey[index]) != kAsiGood ) {
                ads_printf("\nCan't bind the input parameter %d", index) ;
                printAsiErr(csr) ;
                break ;
            }
        }
          /* Check exit condition */
        if ( index < KeyColQty )
            break ;
          /* Open the cursor */
        if ( asi_open(csr) != kAsiGood ) {
            ads_printf("\nCan't open the cursor") ;
            printAsiErr(csr) ;
            break ;
        }   
          /* Fetch */
        if ( asi_fetch(csr) != kAsiGood ) {
            ads_printf("\nCan't fetch for the first row") ;
            printAsiErr(csr) ;
            break ;
        }
          /* Get the current row values */
        if ( csr_getVals(csr, pRow, pColQty) != kAsiGood ) {
            ads_printf("\nCan't get the row values") ;
            printAsiErr(csr) ;
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( csr != 0L ) {
          /* Close the cursor */
        asi_close(csr) ;
          /* Destroy the cursor descriptor */
        asi_destroy_csr(&csr) ;
    }
    if ( stm != 0L ) {
          /* Deallocate the statement desc */
        asi_dealloc_stm (stm);
          /* Free the statement dsc */
        asi_destroy_stm(&stm) ;
    }
      /* Free the ro values */
    if ( retCode != kAsiGood ) {
        asei_destroy_cdscpack(pRow, *pColQty) ;
    }
      /* Free the allocated static buffer */
    addtoken(FREE_TOKENBUF) ;   
    return retCode ;
} /* end of lp_getRow() */

/****************************************************************************/
/*.doc lp_print(internal) */
/*+
  Prints the Link Path Structure
-*/
/****************************************************************************/
static void                               
/*FCN*/lp_print (ASE_LPDSC lp) 
{
    char buf[BUFLEN] ;        /* The buffer for printing */
    ASICOLDSC *pKey=NULL ; /* The key column desc. array */
    int ColQty ;                /* The key columns quantity */         

      /* Print the Table Path */
    ase_lp_getName(lp, buf, BUFLEN, kAseDOCode) ;
    ads_printf("\nDO: [%s]", buf) ;
      /* Print the LPN */
    ase_lp_getName(lp, buf, BUFLEN, kAseLpnCode) ;
    ads_printf("\nLPN: [%s]", buf) ;
      /* Get the key description */
    if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) == kAsiGood ) {
          /* Print the key desc */
        pack_printCols(pKey, ColQty) ;
        /* Free the key descriptors */
        asei_destroy_cdscpack(&pKey, ColQty) ;
    } else {
        ads_printf("\nCan't get the Key Description") ;
        printAseErr(lp) ;
    }
} /* end of lp_print() */

/****************************************************************************/
/*.doc lp_printPath(internal) */
/*+
  Analyzes the link path descriptor and prints its attributes
-*/
/****************************************************************************/
static void                               
/*FCN*/lp_printPath (ASE_LPDSC lp) 
{
    char buf[BUFLEN] ;      /* The buffer for printing */
    char *pBuf=NULL ;         /* The pointer to the buffer */
    int BufLen ;              /* The buffer length */
    int Status ;              /* The DO status */

      /* Print the Link Path Code value */
    ads_printf("\nPath Code: %d", ase_lp_getPathCode(lp)) ;

      /* Demonstrates the buffer dynamical allocating */
    if ( (BufLen=ase_lp_getNameSize(lp, kAsePathCode)) > 0 ) {
          /* Allocate the dynamical buffer */
        if ( (pBuf=(char*)calloc(1, BufLen)) == NULL ) {
            ads_abort("No memory") ;
            return ;
        }
          /* Fill the buffer with the Full Path */
        ase_lp_getName(lp, pBuf, BufLen, kAsePathCode) ;
          /* Print the Database Object Reference */
        ads_printf("\nEntered DOR: [%s]", pBuf) ;
          /* Free the  dynamical buffer */
        free (pBuf) ;
    } else {
        ads_printf("\nAnonymous Reference") ;
    }

      /* Other DO Path names are get into the 'static' buffer */
      /* Get Environment name */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseEnvCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nEnvironment: %s", buf) ;
      /* Get Catalog name */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseCatCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nCatalog: %s", buf) ;
      /* Get Schema name */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseSchemaCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nSchema: %s", buf) ;
      /* Get Table Name */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseTableCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nTable: %s", buf) ;
      /* Get LPN */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseLpnCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nLink Path Name: %s", buf) ;
      /* Get the DO path without LPN */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseDOCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nDO Path: %s", buf) ;
      /* Get the SQL path */
    if ( ase_lp_getName(lp, buf, BUFLEN, kAseSQLCode) != kAsiGood ) {
        buf[0] = '\0' ;
    }
    ads_printf("\nSQL Path: %s", buf) ;

    pauseInput("\nPress any key for the status information...") ;
      /* Analyze the status masks */
    Status = ase_lp_getStatus(lp) ;
    if ( Status & ASE_DO_CURRENT ) {
        ads_printf("\nDO is the current") ;
    }
    if ( Status & ASE_DO_REG ) {
        ads_printf("\nDO is registered") ;
        if ( ase_lp_isUpdatable(lp) == kAsiGood ) {
            ads_printf("\nThe subordinate LPN(s) and its links can be modified") ;
        } else {
            /* Clear the non-updatability reasons data */
            ase_dsc_errClear(lp) ;
        }
    }
    if ( Status & ASE_DO_CON ) {
        ads_printf("\nEnvironment is connected") ;
    } else {
        ads_printf("\nEnvironment is not connected") ;
    }
    if ( Status & ASE_DO_EXIST ) {
        ads_printf("\nDO exist in the database") ;
    } 
    if ( Status & ASE_DO_UNKNOWN ) {
        ads_printf("\nCan't check whether the DO exist in the database") ;
    } 
    if ( !(Status & ASE_DO_EXIST) && ! (Status & ASE_DO_UNKNOWN) ) {
      /* DO definitely doesn't exist */
        ads_printf("\nDo doesn't exist in the database") ;
    }
    if ( Status & ASE_DO_WRONGKEY ) {
        ads_printf("\nWrong registered key column names for table") ;
    } 
    if ( Status & ASE_DO_WRONGKEYTYPE ) {
        ads_printf("\nWrong registered key column types for table") ;
    } 
} /* end of lp_printPath() */

/****************************************************************************/
/*.doc lp_printStat(internal) */
/*+
  Analyzes the link path descriptor and prints the related information
-*/
/****************************************************************************/
static void                               
/*FCN*/lp_printStat (ASE_LPDSC lp) 
{
    ASE_LSDSC   ls=ASE_DSC_NULL ;  /* The link selection descriptor */
    ads_name      ssname ;              /* The Entity Selection Name */
    struct resbuf *pBuf=NULL ;          /* The result buffer for names */
    long          Len=0L ;              /* Selection set length */

    ads_name_clear(ssname) ;         /* Clear the ent sel name */

      /* Get the related links quantity */
    if ( ase_lp_getStatus(lp) & ASE_DO_REG ) {
          /* Print the related link path names */
        if ( (pBuf = ase_lp_getLinkNames(lp)) != NULL ) {
            pauseInput("\nPress key for printing related LPNs") ;
            printBufNames(pBuf) ;
        } else {
            ads_printf("\nCan't get the LPNs list") ;
            printAseErr(lp) ;
        }
        ads_relrb(pBuf) ;
        if ( (ls = ase_dsc_alloc(AseAppl, kAseApiLinkSel)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Selection descriptor") ;
            return ;
        }
          /* Init by the given Link Path Descriptor */
        if ( ase_ls_initLpDsc(ls, lp) != kAsiGood ) {
            if ( ase_dsc_errDsc(ls, 0) != eAseEDscApi ||
                 ase_dsc_errCode(ls, 0) != eAseApiErrSelEmpty ) {
                ads_printf("\nLink Selection creating problem") ;
                printAseErr(ls) ;
            } else {
                /* No related links */
                ads_printf("\nNo Links for the DO exist") ;
            }
            ase_dsc_free(&ls) ;
            return ;
        }
          /* Get the links quantity */
        ads_printf("\nRelated links #%ld", ase_ls_getQty(ls)) ;
          /* Get the entity selection set name */
        if ( ase_ls_getEntSel(ls, ssname) == kAsiGood ) {
              /* Get the entities quantity */
            if ( ads_sslength(ssname, &Len) == RTNORM ) {
                ads_printf("\nRelated entities #%ld", Len) ;
            } else {
                ads_printf("\nWrong entity selection is returned") ;
            }
              /* Free the allocated selection */
            ads_ssfree(ssname) ;
        } else {
            ads_printf("\nCan't get the links selection for DO") ;
            printAseErr(ls) ;
        }
          /* Get the related Xref/Block names */
        if ( (pBuf=ase_ls_getXNames(ls)) != NULL ) {
            pauseInput("\nPress key for Xref/Block names printing...") ;
            printBufNames(pBuf) ;
            ads_relrb(pBuf) ;
        } else {
            ads_printf("\nNo related Xref(s)/Block(s) are available") ;
            printAseErr(ls) ;
        }
          /* Free the link selection descriptor */
        ase_dsc_free(&ls) ;
    }
} /* end of lp_printStat() */

/****************************************************************************/
/*.doc csr_scroll(internal) */
/*+
  This function scans the opened cursor and
  supports the link manipulation.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_scroll(
           ASICURSOR csr,   /* The cursor descriptor */
           ASE_LPDSC lp     /* The Link Path descriptor */
           ) 
{
    char buf[BUFLEN] ;                 /* The buffer for entering */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */
    EAsiBoolean rCode=kAsiGood ;       /* The fetching resulting code */
    int retword ;                      /* ads_getkword() returning value */

    /* The initial checking fetch */
    if ( asi_fetch(csr) != kAsiGood ) {
        printAsiErr(csr) ;
        return kAsiBad ;
    }
    do {
          /* Loop for the asking LPN options */
        do {
            if ( rCode == kAsiGood ) {
                csr_printRow(csr) ;
            } else {
                printAsiErr(csr) ;
            }
            if ( ads_initget(0, "N P F L V E M R X") != RTNORM ) {
                break ;
            }
              /* Next/Previous/First/Last/View/Erase/Make/Reload DA/<eXit> */
            retword=ads_getkword(
                      "\nNext/Previous/First/Last/View/Erase/Make/Reload DA/<eXit>:", 
                      buf) ;
            if ( retword != RTNORM && retword != RTNONE ) {
                break ;
            }
            if ( retword == RTNONE || buf[0] == '\0' || buf[0] == 'X' ) {
                retCode = kAsiGood ;
                break ;
            }
            switch(buf[0]) {
            case 'N':                  /* NEXT */
                rCode = asi_fetch (csr);
                break ;
            case 'P':                  /* PREVIOUS */
                rCode = asi_fetchPrior (csr);
                break ;
            case 'F':                  /* FIRST */
                rCode = asi_fetchFirst (csr);
                break ;
            case 'L':                  /* LAST */
                rCode = asi_fetchLast (csr);
                break ;
            case 'V':                  /* VIEW */
                csr_viewLinks(csr, lp) ;
                break ;
            case 'E':                  /* ERASE */
                csr_eraseLinks(csr, lp) ;
                break ;
            case 'M':                 /* MAKE */
                csr_makeLink(csr, lp) ;
                break ;
            case 'R':                /* RELOAD DA */
                csr_reloadDA(csr, lp) ;
                break ;
            }
        } while(1) ;
    } while(0) ;
    return retCode ;
} /* end of csr_scroll() */

/****************************************************************************/
/*.doc csr_viewLinks(internal) */
/*+
  This function prints the links related with the curren cursor row
  and the specified Link Path 
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_viewLinks(ASICURSOR csr, ASE_LPDSC lp) 
{
    ASE_LSDSC ls=ASE_DSC_NULL ;       /* The link selection buffer */
    EAsiBoolean retCode = kAsiBad ;   /* The returning code */

    do {
          /* Get the link selection */
        if ( (ls=csr_getLinks(csr, lp)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Check the length of the link Selection */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nNo Links") ;
            retCode = kAsiGood ;
            break ;
        }
          /* Print the Link Selection */
        ls_print(ls, ASE_DSC_NULL, (ASICOLDSC*)NULL, 0) ;
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&ls) ;
    return retCode ;
} /* end of csr_viewLinks() */

/****************************************************************************/
/*.doc csr_eraseLinks(internal) */
/*+
  This function erases the links related with the curren cursor row
  and the specified Link Path 
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_eraseLinks(ASICURSOR csr, ASE_LPDSC lp) 
{
    ASE_LSDSC ls=ASE_DSC_NULL ;       /* The link selection buffer */
    EAsiBoolean retCode = kAsiBad ;   /* The returning code */

    do {
          /* Get the link selection */
        if ( (ls=csr_getLinks(csr, lp)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Check the length of the link Selection */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nNo Links") ;
            retCode = kAsiGood ;
            break ;
        }
          /* Check, whether the links are updatable */
        if ( ase_ls_isUpdatable(ls) != kAsiGood ) {
            ads_printf("\nThe Link Selection isn't updatable") ;
            printAseErr(ls) ;
            retCode = kAsiGood ;
            break ;
        }
          /* Erase the links */
        if ( ase_ls_erase(ls) != kAsiGood ) {
            ads_printf("\nCan't erase the links from Link Selection") ;
            printAseErr(ls) ;
            break ;
        }
          /* Remove the LPN from LP */
        if ( ase_lp_setName(lp, "", kAseLpnCode) != kAsiGood ) {
            ads_printf("\nCan't nullify the LPN") ;
            printAseErr(lp); 
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&ls) ;
    return retCode ;
} /* end of csr_eraseLinks() */

/****************************************************************************/
/*.doc csr_makeLink(internal) */
/*+
  This function makes the links to the current row of the specified cursor
  The link type - Entity Link or DA Link is asked.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_makeLink(ASICURSOR csr, ASE_LPDSC lp) 
{
    char  buf[BUFLEN] ;             /* The buffer */
    EAsiBoolean retCode = kAsiBad ;   /* The returning code */

    do {
          /* Ask for the DO path entering */
        if ( ads_getstring(0, "Da/<Entity>:", buf) != RTNORM ) {
            ads_printf("\nNo input") ;
            ase_dsc_free(&lp) ;
            break ;
        }
        if ( buf[0] == '\0' || buf[0] == 'e' || buf[0] == 'E' ) {
            retCode = link_entMake(csr, lp) ;
        } else if ( buf[0] == 'd' || buf[0] == 'D' ) {
            retCode = link_daMake(csr, lp) ;
        } else {
            ads_printf("\nWrong input");
            continue ;
        }
    } while(0) ;
    return retCode ;
} /* end of csr_makeLink() */

/****************************************************************************/
/*.doc csr_reloadDA(internal) */
/*+
  Reloads the DA, related with the current row of the specified cursor.
  If DA are relaoded succesfully or there is no DAs related
  with the specified Link Path and the current row,
  returns kAsiGood. 
  Returns kAsiBad if somethign is wrong.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_reloadDA(ASICURSOR csr, ASE_LPDSC lp) 
{
    ASE_LSDSC ls=ASE_DSC_NULL ;      /* The set of the related DA links */
    ASE_LINKDSC link=ASE_DSC_NULL;   /* The Link Descriptor */
    ASICOLDSC *pDACols=NULL ;        /* The DA values */
    LinkID ID ;                      /* The link identifier */
    long linkQty ;                   /* The DA links quantity */
    long index ;                     /* scanning index */
    int DAColQty=0 ;                 /* DA values quantity */
    EAsiBoolean retCode = kAsiBad ;  /* The returning code */

    do {
          /* Get the link selection */
        if ( (ls=csr_getLinks(csr, lp)) == ASE_DSC_NULL ) {
            break ;
        }
          /* Check the length of the link Selection */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nNo Links") ;
            retCode = kAsiGood ;
            break ;
        }
          /* Filter the links */
        if ( ase_ls_intersectType(ls, kAseDALink) != kAsiGood ) {
            ads_printf("\nError in the link selection filtering") ;
            printAseErr(ls) ;
            break ;
        }
          /* Check the length of the link Selection now */
        if ( (linkQty=ase_ls_getQty(ls)) == 0L ) {
            ads_printf("\nNo DA Links") ;
            retCode = kAsiGood ;
            break ;
        }
          /* Allocate the Link Descripotor */
        if ( (link=ase_dsc_alloc(AseAppl, kAseApiLink)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Descriptor") ;
            break ;
        }
          /* Scan the links */
        for ( index = 0L ; 
              index < linkQty ;
              index++ ) {
              /* Get the Link descriptor */
            if ( (ID=ase_ls_getId(ls, index)) == LINKID_NULL ) {
                ads_printf("\nWrong Link ID was got") ;
                printAseErr(ls) ;
                break ;
            }
              /* Init the Link by the ID */
            if ( ase_link_initId(link, ID) != kAsiGood ) {
                ads_printf("\nCan't init the link by the ID %ld", ID) ;
                printAseErr(link) ;
                break ;
            }
              /* Check the Link Updatability */
            if ( ase_link_isUpdatable(link) != kAsiTrue ) {
                ads_printf("\nLink %ld is unupdatable", ID) ;
                continue ;
            }
              /* Get the DA columns */
            if ( ase_link_getDACols(link, &pDACols, &DAColQty) != kAsiGood ) {
                ads_printf("\nCan't get the DA columns") ;
                printAseErr(link) ;
                break ;
            }
              /* Extract the new DA column values */
            if ( csr_getVals(csr, &pDACols, &DAColQty) != kAsiGood ) {
                ads_printf("\nCan't get the new DA column values") ;
                break ;
            }
              /* Update the new DA column values */
            if ( ase_link_setDAValues(link, pDACols, DAColQty) != kAsiGood ) {
                ads_printf("\nCan't update the new DA column values") ;
                printAseErr(link) ;
                break ;
            }
              /* Update the DA link */
            if ( ase_link_update(link) != kAsiGood ) {
                ads_printf("\nCan't update the DA link") ;
                printAseErr(link) ;
                break ;
            }
              /* Desctroy the DA column values */
            asei_destroy_cdscpack(&pDACols, DAColQty) ;
        }
          /* Check the loop exit condition */
        if ( index < linkQty ) {
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
      /* Destroy DA column values */
    asei_destroy_cdscpack(&pDACols, DAColQty) ;
      /* Free the Link Selection */
    ase_dsc_free(&ls) ;
    return retCode ;
} /* end of csr_reloadDA() */

/****************************************************************************/
/*.doc csr_getVals(internal) */
/*+
  Extracts the values from the cursor in accordance
  with the columns description. If *pVals==(ASICOLDSC*)NULL, 
  then this function allocates the
  packet of the ASICOLDSC and retreives all columns descriptions.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/csr_getVals(ASICURSOR csr, 
                  ASICOLDSC *pVals[],
                  int *pColQty) 
{
    ASICOLDSC cds ;    /* The column descriptor */
    EAsiBoolean retCode=kAsiBad ; /* The returning code */
    int index ;        /* main scanning index */
    int jndex ;        /* second scanning index */

    do {
        if ( *pVals == (ASICOLDSC*)NULL ) {
            *pColQty = asi_colcount(csr) ;
              /* Allocate the packet */
            if ( (*pVals=asei_constr_cdscpack(*pColQty)) ==
                  (ASICOLDSC*)NULL ) {
                ads_abort("\nCan't allocate the packet") ;
                break ;
            }
            for ( index = 0 ; index < *pColQty ; index++ ) {
                  /* Get the column & data desc and */
                if ( asei_cds(csr, index, &cds) != kAsiGood ) {
                    ads_abort("\nCan't get the column descriptor") ;
                    break ;
                }
                  /* insert it into the packet */
                if ( ((*pVals)[index]=cds) == 0L ) {
                    ads_abort("\nCan't duplicatre column description") ;
                    break ;
                }
            }
            if ( index >= *pColQty ) {
                retCode = kAsiGood ;
            }
            break ;
        }
        retCode = kAsiGood ;
        for ( index = 0 ; index < *pColQty ; index++ ) {
            for ( jndex = 0 ; jndex < asi_colcount(csr) ; jndex++ ) {
                  /* Get the column & data desc and */
                if ( asei_cds(csr, jndex, &cds) != kAsiGood ) {
                    ads_abort("\nCan't get the column descriptor") ;
                    retCode = kAsiBad ;
                    break ;
                }
                  /* Compare two column desc */
                if ( asei_cdsc_cmpname((*pVals)[index], cds) ) {
                      /* insert it into the packet */
                    if ( ((*pVals)[index]=cds) == 0L ) {
                        ads_abort("\nCan't duplicatre column description") ;
                        retCode = kAsiBad ;
                        break ;
                    }
                    break ;
                }
                asei_destroy_cdsc(&cds) ;
            }
            if ( retCode != kAsiGood ) {
                break ;
            }
        }
    } while(0) ;
    return retCode ;
} /* end of csr_getVals() */

/****************************************************************************/
/*.doc csr_getLinks(internal) */
/*+
  Gets the link selection for the links related with the
  current row of the specified cursor and related with the
  specified Link Path. The links quantity should be checked 
  with the ase_ls_getQty().
  Return ASE_DSC_NULL if something is wrong.
-*/
/****************************************************************************/
static ASE_LSDSC   
/*FCN*/csr_getLinks(ASICURSOR csr,
                    ASE_LPDSC lp) 
{
    ASE_LSDSC lsret=ASE_DSC_NULL ;   /* The returning Link Selection */
    ASICOLDSC *pKey=NULL ;           /* The Key values buffer */
    int ColQty ;                     /* The columns quantity */
    EAsiBoolean retCode=kAsiBad ;    /* The exit condition */

    do {
          /* Allocate the link selection */
        if ( (lsret=ase_dsc_alloc(AseAppl, kAseApiLinkSel)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Sel descriptor") ;
            break ;
        }
          /* Check the Link Path */
        if ( ase_lp_getPathCode(lp) == kAseLpnCode ) {
              /* LPN is set - get the Key Description */
            if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) != kAsiGood ) {
                ads_printf("\nCan't get the Key Description") ;
                printAseErr(lp) ;
                break ;
            }
        }
          /* Get the Key Values of the current row */
          /* If the Link Path doesn't have the LPN */
          /* specified - ask for the all row values */
        if ( csr_getVals(csr, &pKey, &ColQty) != kAsiGood ) {
            ads_printf("\nCan't get the key values from row") ;
            break ;
        }
          /* Init the link selection by the Link Path */
          /* and the row values */
        if ( ase_ls_initLpDscKey(lsret, lp, pKey, ColQty) != kAsiGood ) {
            if ( ase_dsc_errDsc(lsret, 0) != eAseEDscApi ||
                ase_dsc_errCode(lsret, 0) != eAseApiErrSelEmpty ) {
                ads_printf("\nLink Selection creating problem") ;
                printAseErr(lsret) ;
            } else {
                  /* No related links */
                retCode = kAsiGood ;
            }
            break ;
        }
          /* Check the length of the link Selection */
        if ( ase_ls_getQty(lsret) == 0L ) {
            ads_printf("\nWrong Link Selection length") ;
            printAseErr(lsret) ;
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    asei_destroy_cdscpack(&pKey, ColQty) ;
    if ( retCode != kAsiGood ) {
        ase_dsc_free(&lsret) ;
    }
    return lsret ;
} /* end of csr_getLinks() */

/****************************************************************************/
/*.doc csr_printRow(internal) */
/*+
  Prints the current row of the specified cursor
-*/
/****************************************************************************/
static void        
/*FCN*/csr_printRow(ASICURSOR csr) 
{
    ASICOLDSC col ;           /* The column descriptor with the data */
    ASIIDENT ident ;          /* Column identifier */
    char buf[BUFLEN] ;        /* The buffer for printing values */
    EAsiBoolean isNull ;      /* Null value indicator */
    int index ;               /* The row column scanning index */

    for ( index = 0 ; index < asi_colcount(csr) ; index++ ) {
          /* Get the column descriptor with the data */
        if ( asei_cds(csr, index, &col) != kAsiGood ) {
            ads_printf("\nCan't get the column descriptor") ;
            printAsiErr(csr) ;
            break ;
        }
          /* Get the ident */
        if ( asi_cdsc_name(col, &ident) != kAsiGood ) {
            ads_printf("\nCan't get the column identifier") ;
        }
          /* Get the ident name */
        if ( asi_get_ident(ident, buf, BUFLEN) == NULL ) {
            ads_printf("\nCan't get the identifier name") ;
            asi_destroy_ident(&ident) ;
            asei_destroy_cdsc(&col) ;
            break ;
        }
        asi_destroy_ident(&ident) ;
          /* Print the ident name */
        ads_printf("\n %s: ", buf) ;
        asei_cdsc_rtype(col, &isNull)  ;
        if ( isNull == kAsiTrue ) {
              /* Null value */
            buf[0] = '.' ;
            buf[1] = '\0' ;
        } else {
              /* Get the column value as the string */
            if ( asei_cdsc_getstr(col, buf, BUFLEN) != kAsiGood ) {
                ads_printf("\nCan't get the value") ;
                asei_destroy_cdsc(&col) ;
                break ;
            }
        }
        ads_printf("%s", buf) ;
        asei_destroy_cdsc(&col) ;
    }
} /* end of csr_printRow() */

/****************************************************************************/
/*.doc ls_scan(internal) */
/*+
  Scans and manipulates with the links for the specified Link Selection.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/ls_scan(ASE_LSDSC ls) 
{
    ASE_LINKDSC link=ASE_DSC_NULL ;    /* The current link buffer */
    ASE_LPDSC lp=ASE_DSC_NULL ;        /* Link Path of the current link */
    ASICOLDSC *pKey=(ASICOLDSC*)NULL ; /* Key buffer */
    ASICOLDSC *pRow=(ASICOLDSC*)NULL ; /* Row values buffer */
    char buf[BUFLEN] ;                 /* The buffer for entering */
    long pos=0L ;                      /* The current position in Link Sel */
    long length=ase_ls_getQty(ls) ;    /* The Link Selection length */
    LinkID ID=LINKID_NULL;             /* The current Link Identifier */
    long newID ;                       /* For the new Link Identifier */
    int ColQty ;                       /* Table columns quantity */
    int KeyColQty ;                    /* Key columns quantity */
    int retword ;                      /* ads_getkword() returning value */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */

      /* Allocate the Link Descriptor */
    if ( (link=ase_dsc_alloc(AseAppl, kAseApiLink)) == ASE_DSC_NULL ) {
        ads_abort("\nCan't allocate the Link Descriptor") ;
        return kAsiBad ;
    }
      /* Allocate the Link Path Descriptor */
    if ( (lp=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) == ASE_DSC_NULL ) {
        ads_abort("\nCan't allocate the Link Path Descriptor") ;
        return kAsiBad ;
    }
    do {
          /* Check the Link Selection length */
        if ( length <= 0L ) {
            ads_printf("\nNo Links") ;
            break ;
        }
          /* Get the Link Identifier */
        if ( ase_ls_getId(ls, pos) != ID ) {
              /* Check the Link Identifier */
            if ( (ID = ase_ls_getId(ls, pos)) == LINKID_NULL ) {
                ads_printf("\nWrong ID is got") ;
                printAseErr(ls) ;
                break ;
            }
              /* Initialize the Link Descriptor */
              /* by the Link Identifier */
            if ( ase_link_initId(link, ID) != kAsiGood ) {
                ads_printf("\nCan't get the data for the link %ld", ID) ;
                break ;
            }
              /* Get the Link Path name */
            if ( ase_link_getName(link, buf, BUFLEN) != kAsiGood ) {
                ads_printf("\nCan't get the Link Path Name") ;
                printAseErr(link) ;
                break ;
            }
              /* Check whether the same Link Path */
              /* already exist */
            if ( ! ase_lp_cmpName(lp, buf, kAseLpnCode) ) {
                  /* Init the Link Path by the new LPN */
                if ( ase_lp_initName(lp, buf) != kAsiGood ) {
                    ads_printf("\nWrong LPN is got") ;
                    printAseErr(lp) ;
                    break ;
                }
                  /* Get the key buffer */
                if ( ase_lp_getKeyDsc(lp, &pKey, &KeyColQty) != kAsiGood ) {
                    ads_printf("\nCan't get the Key description") ;
                    printAseErr(lp) ;
                    break ;
                }
            }
        }
          /* Print the Link Data */
        link_print(link, pKey, KeyColQty) ;
          /* Print the Link Quatity */
        ads_printf("\nPosition:#%ld   Links Quantity: #%ld", pos, length) ;
          /* Next/Previous/First/Last/Add/Delete/Edit/Row/<eXit> */
        if ( ads_initget(0, "N P F L A D E R X") != RTNORM ) {
            break ;
        }
        retword=ads_getkword(
                   "\nNext/Previous/First/Last/Add/Delete/Edit/Row/<eXit>:", 
                   buf) ;
        if ( retword != RTNORM && retword != RTNONE ) {
            break ;
        }
        if ( retword == RTNONE || buf[0] == '\0' || buf[0] == 'X' ) {
            retCode = kAsiGood ;
            break ;
        }
        switch(buf[0]) {
        case 'N':                      /* NEXT */
            if ( pos < ase_ls_getQty(ls)-1 )
                pos++ ;
            break ;
        case 'P':                      /* PREVIOUS */
            if ( pos > 0L ) {
                pos-- ;
            }
            break ;
        case 'F':                      /* FIRST */
            pos = 0L ;
            break ;
        case 'L':                      /* LAST */
            pos = length-1 ;
            break ;
        case 'A':                      /* ADD */
              /* Ask for the new identifier number */
            if ( ads_getstring(0, "\nEnter the Link ID:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Check the number */
            if ( (newID=(long)atol(buf)) == 0L && buf[0] != '0' ) {
                ads_printf("\nThe number is required") ;
                continue ;
            }
              /* Check whether or not the new */
              /* Link Identifier already */
              /* exist in the Link Selection */
            if ( ase_ls_membId(ls, (LinkID)newID) != -1L ) {
                ads_printf("\nSuch a ID already exist") ;
                continue ;
            }
              /* Add the identifier */
              /* to the Link Selection */
            if ( ase_ls_addId(ls, (LinkID)newID) != kAsiGood ) {
                ads_printf("\nCan't add the link identifier") ;
                printAseErr(ls) ;
                break ;
            }
              /* Get the new position */
            if ( (pos=ase_ls_membId(ls, (LinkID)newID)) != -1L ) {
                ads_printf("\nSuch a ID already exist") ;
                break ;
            }
              /* Assign the new current identifier value */
            ID = (LinkID)newID ;
            break ;
        case 'D':                      /* DELETE */
            /* Check the Link Updatability */
            if ( ase_link_isUpdatable(link) != kAsiTrue ) {
                ads_printf("\nThe link isn't updatable") ;
                printAseErr(link) ;
                break ;
            }
              /* Remove the link */
            if ( ase_link_remove(link) != kAsiGood ) {
                ads_printf("\nCan't delete the link") ;
                printAseErr(link) ;
                break ;
            }
              /* Erase the link ID from the Link Selection */
            if ( ase_ls_delId(ls, pos) != kAsiGood ) {
                ads_printf("\nCan't remove the Link Id") ;
                printAseErr(ls) ;
            }
              /* Recalculate the new position */
            if ( pos == length-1 ) {
                pos-- ;
            }
            length-- ;
            break ;
        case 'E':                      /* EDIT */ 
            link_edit(link, lp, pKey, KeyColQty) ;
            break ;
        case 'R':                      /* ROW */
              /* Connect to the Env */
            if ( isConnected(lp) != kAsiTrue ) {
                if ( connect(lp) != kAsiGood ) {
                    break ;
                }
            }
              /* Get the row values */
            if ( lp_getRow(lp, pKey, KeyColQty,
                           &pRow, &ColQty) != kAsiGood ) {
                ads_printf("\nCan't get the row values for link") ;
                break ;
            }
              /* Print the values */
            pack_printVals(pRow, ColQty) ;
              /* Free the values */
            asei_destroy_cdscpack(&pRow, ColQty) ;
        }
    } while(1) ;
    ase_dsc_free(&link) ;
    ase_dsc_free(&lp) ;
    asei_destroy_cdscpack(&pKey, KeyColQty) ;
    return retCode ;
} /* end of ls_scan() */

/****************************************************************************/
/*.doc ls_create(internal) */
/*+
  Creates the Link Selection asking the user
  with the criterias. Returns ASE_DSCNULL in the
  case of the error.
-*/
/****************************************************************************/
static ASE_LSDSC
/*FCN*/ls_create() 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;        /* The Link Path Descriptor */
    ASE_LSDSC ls=ASE_DSC_NULL ;        /* Returning Link Selection desc */
    ASICOLDSC *pKey=(ASICOLDSC*)NULL ; /* The Key packet */
    ads_point pt ;                     /* The point to entity picking */
    ads_name EntName ;                 /* The Entity Name */
    ads_name EntSelName ;              /* Entity Selection name */
    char buf[BUFLEN] ;               /* The input buffer */
    char sqlbuf[BUFLEN] ;            /* The SQL condition buffer */
    EAseLinkType Type ;                /* The Link Type */
    int ColQty ;                       /* The Key Columns Quantity */
    int i ;                            /* The option number */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */

    do {
          /* Print the menu */
        ads_printf("\nLink Selection Creating") ;
        ads_printf("\n  0 - Exit") ;
        ads_printf("\n  1 - Link Type") ;
        ads_printf("\n  2 - Entity") ;
        ads_printf("\n  3 - Entity Selection") ;
        ads_printf("\n  4 - Xref/Block Name") ;
        ads_printf("\n  5 - Link Path Name") ;
        ads_printf("\n  6 - Database Object Reference") ;
        ads_printf("\n  7 - Link Path Name & Entity") ;
        ads_printf("\n  8 - Database Object Reference & Entity") ;
        ads_printf("\n  9 - Link Path Name & Entity Selection") ;
        ads_printf("\n 10 - Database Object Reference & Entity Selection") ;
        ads_printf("\n 11 - Link Path Name & SQL Condition") ;
        ads_printf("\n 12 - Database Object Reference & SQL Condition") ;
        ads_printf("\n 13 - Link Path Name & Key Values") ;
        ads_printf("\n 14 - Database Object Reference & Key Values") ;
          /* Ask for the option number */
        if ( ads_getstring(0, "\nEnter the option number <0>:", buf) 
             != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
          /* Defautl input check */
        if ( buf[0] == '\0' ) {
            break ;
        }
          /* Number test */
        if ( (i=atoi(buf)) == 0 && buf[0] != '0' ) {
            ads_printf("\nThe number is required") ;
            continue ;
        }
          /* Check the upper limit */
        if ( i > 14 || i < 0 ) {
            ads_printf("\nWrong option number") ;
            continue ;
        }
          /* Allocate the Link Selection descriptor */
        if ( (ls=ase_dsc_alloc(AseAppl, kAseApiLinkSel)) 
             == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Selection descriptor") ;
            break ;
        }
        switch(i) {
        case 1:                        /* Link Type */
              /* Ask for the Link Type */
            if ( ads_getstring(0, "\nDA Link/<Entity Link>:", buf) 
                 != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Set the link type */
            if ( buf[0] == '\0' || buf[0] == 'E' || buf[0] == 'e' ) {
                Type = kAseEntityLink ;
            } else {
                Type = kAseDALink ;
            }
              /* Initialize the Link Selection by the */
              /* link type */
            retCode = ase_ls_initType(ls, Type) ;
            break ;
        case 2:                        /* Entity */
              /* Ask for the entity picking */
            if ( ads_entsel("\nSelect object:", EntName, pt) != RTNORM ) {
                ads_printf("\nWrong entity name input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* entity name */
            retCode = ase_ls_initEnt(ls, EntName) ;
            break ;
        case 3:                        /* Entity Selection */
              /* Ask for the entity selection */
            if ( ads_ssget(NULL, NULL, NULL, NULL, EntSelName) != RTNORM ) {
                ads_printf("\nWrong entity selection") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* entity selection set name */
            retCode = ase_ls_initSel(ls, EntSelName) ;
              /* Free the entity selection */
            ads_ssfree(EntSelName) ;
            break ;
        case 4:                        /* Xref/Block Name */
              /* Ask for the Xref/Block name */
            if ( ads_getstring(0, "\nXref/Block name:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Xref/Block name */
            retCode = ase_ls_initXName(ls, buf) ;
            break ;
        case 5:                        /* Link Path Name */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Name */
            retCode = ase_ls_initLp(ls, buf) ;
            break ;
        case 6:                        /* Database Object Reference */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Descriptor */
            retCode = ase_ls_initLpDsc(ls, lp) ;
            break ;
        case 7:                        /* Link Path Name & Entity */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Ask for the entity picking */
            if ( ads_entsel("\nSelect object:", EntName, pt) != RTNORM ) {
                ads_printf("\nWrong entity name input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Name and entity name */
            retCode = ase_ls_initLpEnt(ls, buf, EntName) ;
            break ;
        case 8:                        /* Database Object Reference & Entity */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Ask for the entity picking */
            if ( ads_entsel("\nSelect object:", EntName, pt) != RTNORM ) {
                ads_printf("\nWrong entity name input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Descriptor and entity name */
            retCode = ase_ls_initLpDscEnt(ls, lp, EntName) ;
            break ;
        case 9:                        /* Link Path Name & Entity Selection */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Ask for the entity selection */
            if ( ads_ssget(NULL, NULL, NULL, NULL, EntSelName) != RTNORM ) {
                ads_printf("\nWrong entity selection") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Name and entity selection set name */
            retCode = ase_ls_initLpSel(ls, buf, EntSelName) ;
              /* Free the entity selection */
            ads_ssfree(EntSelName) ;
            break ;
        case 10:                       /* Database Object Reference & Entity Selection */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Ask for the entity selection */
            if ( ads_ssget(NULL, NULL, NULL, NULL, EntSelName) != RTNORM ) {
                ads_printf("\nWrong entity selection") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Descriptor and entity selection set name */
            retCode = ase_ls_initLpDscSel(ls, lp, EntSelName) ;
              /* Free the entity selection */
            ads_ssfree(EntSelName) ;
            break ;
        case 11:                       /* Link Path Name & SQL Condition */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Ask for the SQL condition */
            if ( ads_getstring(0, "\n<WHERE> condition:", sqlbuf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Name and SQL condition */
            retCode = ase_ls_initLpCond(ls, buf, sqlbuf) ;
            break ;
        case 12:                       /* Database Object Reference & SQL Condition */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiTrue)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Ask for the SQL condition */
            if ( ads_getstring(0, "\n<WHERE> condition:", sqlbuf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Descriptor and SQL condition */
            retCode = ase_ls_initLpDscCond(ls, lp, sqlbuf) ;
            break ;
        case 13:                       /* Link Path Name & Key Values */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Allocate the Link Path descriptor */
            if ( (lp=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) == ASE_DSC_NULL ) {
                ads_abort("\nCan't allocate the Link Path descriptor") ;
                break ;
            }
              /* Init the Link Path descriptor by the LPN */
            if ( ase_lp_initName(lp, buf) != kAsiGood ) {
                ads_printf("\nWrong LPN is entered") ;
                printAseErr(lp) ;
                break ;
            }
              /* Get the key column description */
            if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) != kAsiGood ) {
                ads_printf("\nCan't get the key column description") ;
                printAseErr(lp) ;
                break ;
            }
              /* Ask for the key values entering */
            ads_printf("\nEnter the key values") ;
            if ( pack_edit(pKey, ColQty) != kAsiGood ) {
                ads_printf("\nWrong key input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Name and Key Values */
            retCode = ase_ls_initLpKey(ls, buf, pKey, ColQty) ;
            break ;
        case 14:                       /* Database Object Reference & Key Values */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Check the DOR */
            if ( ase_lp_getPathCode(lp) != kAseLpnCode &&
                 ase_lp_getPathCode(lp) != kAseTableCode ) {
                ads_printf("\nNot the Table Reference is entered") ;
                break ;
            }
              /* Get the description of the columns */
            if ( ase_lp_getPathCode(lp) == kAseLpnCode ) {
                  /* Get the key column description */
                if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) != kAsiGood ) {
                    ads_printf("\nCan't get the key column description") ;
                    printAseErr(lp) ;
                    break ;
                }
                ads_printf("\nEnter the key values") ;
            } else {
                  /* Check whether or not Env is connected */
                  /* and connect in application */
                if ( isConnected(lp) != kAsiTrue &&
                     connect(lp) != kAsiGood ) {
                    break ;
                }
                  /* Get the description of the all table columns */
                if ( lp_getTabCols(lp, &pKey, &ColQty) != kAsiGood ) {
                    ads_printf("\nCan't get the table column desc") ;
                    break ;
                }
                ads_printf("\nEnter the row values") ;
            }
              /* Ask for the values entering */
            if ( pack_edit(pKey, ColQty) != kAsiGood ) {
                ads_printf("\nWrong key input") ;
                break ;
            }
              /* Initialize the Link Selection by the */
              /* Link Path Descriptor and Key Values */
            retCode = ase_ls_initLpDscKey(ls, lp, pKey, ColQty) ;
            break ;
        }
    } while(0) ;
    if ( retCode == kAsiGood ) {
        ads_printf("\nThe Links Quantity #%ld", ase_ls_getQty(ls)) ;
    } else {
          /* Check the Link Selection errors */
        if ( ase_dsc_errQty(ls) ) {
              /* Check if no Link are satisfyed to condition */
            if ( ase_dsc_errDsc(ls, 0) != eAseEDscApi ||
                 ase_dsc_errCode(ls, 0) != eAseApiErrSelEmpty ) {
                ads_printf("\nLink Selection creating problem") ;
                printAseErr(ls) ;
            } else {
                /* No related links */
                ads_printf("\nNo Links correspond to the specified option") ;
            }
        } else {
            ads_printf("\nNo link selection is created") ;
        }
        ase_dsc_free(&ls) ;
    }
      /* Free the Link Path descriptor */
    ase_dsc_free(&lp) ;
      /* Destroy the key packet */
    asei_destroy_cdscpack(&pKey, ColQty) ;
    return ls ;
} /* end of ls_create() */

/****************************************************************************/
/*.doc ls_filter(internal) */
/*+
  This function filters the specified Link Selection.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/ls_filter(ASE_LSDSC ls) 
{
    ASE_LPDSC lp=ASE_DSC_NULL ;        /* The Link Path Descriptor */
    ASICOLDSC *pKey=(ASICOLDSC*)NULL ; /* The Key packet */
    ads_point pt ;                     /* The point to entity picking */
    ads_name EntName ;                 /* The Entity Name */
    ads_name EntSelName ;              /* Entity Selection name */
    char buf[BUFLEN] ;               /* The input buffer */
    char sqlbuf[BUFLEN] ;            /* The SQL condition buffer */
    EAseLinkType Type ;                /* The Link Type */
    int ColQty ;                       /* The Key Columns Quantity */
    int i ;                            /* The option number */
    EAsiBoolean retCode = kAsiBad ;    /* The returning code */

    do {
          /* Clear the Link Selection errors */
        ase_dsc_errClear(ls) ;
          /* Print the menu */
        ads_printf("\nLink Selection Filtering") ;
        ads_printf("\n  1 - Link Type") ;
        ads_printf("\n  2 - Entity") ;
        ads_printf("\n  3 - Entity Selection") ;
        ads_printf("\n  4 - Xref/Block Name") ;
        ads_printf("\n  5 - Link Path Name") ;
        ads_printf("\n  6 - Database Object Reference") ;
        ads_printf("\n  7 - Link Path Name & SQL Condition") ;
        ads_printf("\n  8 - Database Object Reference & SQL Condition") ;
        ads_printf("\n  9 - Link Path Name & Key Values") ;
        ads_printf("\n 10 - Database Object Reference & Key Values") ;
        if ( ads_getstring(0, "\nEnter the option number <0>:", buf) 
             != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
        if ( buf[0] == '\0' ) {
            retCode = kAsiBad ;
            break ;
        }
          /* Number test */
        if ( (i=atoi(buf)) == 0 && buf[0] != '0' ) {
            ads_printf("\nThe number is required") ;
            continue ;
        }
          /* Check the upper limit */
        if ( i >= 10 || i < 0 ) {
            ads_printf("\nWrong option number") ;
            continue ;
        }
        switch(i) {
        case 1:                        /* Link Type */
              /* Ask for the Link Type */
            if ( ads_getstring(0, "\nDA Link/<Entity Link>:", buf) 
                 != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Set the link type */
            if ( buf[0] == '\0' || buf[0] == 'E' || buf[0] == 'e' ) {
                Type = kAseEntityLink ;
            } else {
                Type = kAseDALink ;
            }
              /* Filter the Link Selection by the */
              /* link type */
            retCode = ase_ls_intersectType(ls, Type) ;
            break ;
        case 2:                        /* Entity */
              /* Ask for the entity picking */
            if ( ads_entsel("\nSelect object:", EntName, pt) != RTNORM ) {
                ads_printf("\nWrong entity name input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* entity name */
            retCode = ase_ls_intersectEnt(ls, EntName) ;
            break ;
        case 3:                        /* Entity Selection */
              /* Ask for the entity selection */
            if ( ads_ssget(NULL, NULL, NULL, NULL, EntSelName) != RTNORM ) {
                ads_printf("\nWrong entity selection") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* entity selection set name */
            retCode = ase_ls_intersectSel(ls, EntSelName) ;
              /* Free the entity selection */
            ads_ssfree(EntSelName) ;
            break ;
        case 4:                        /* Xref/Block Name */
              /* Ask for the Xref/Block name */
            if ( ads_getstring(0, "\nXref/Block name:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Xref/Block name */
            retCode = ase_ls_intersectXName(ls, buf) ;
            break ;
        case 5:                        /* Link Path Name */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Name */
            retCode = ase_ls_intersectLp(ls, buf) ;
            break ;
        case 6:                        /* Database Object Reference */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Descriptor */
            retCode = ase_ls_intersectLpDsc(ls, lp) ;
            break ;
        case  7:                       /* Link Path Name & SQL Condition */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Ask for the SQL condition */
            if ( ads_getstring(0, "\n<WHERE> condition:", sqlbuf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Name and SQL condition */
            retCode = ase_ls_intersectLpCond(ls, buf, sqlbuf) ;
            break ;
        case  8:                       /* Database Object Reference & SQL Condition */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiFalse, kAsiTrue)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Ask for the SQL condition */
            if ( ads_getstring(0, "\n<WHERE> condition:", sqlbuf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Descriptor and SQL condition */
            retCode = ase_ls_intersectLpDscCond(ls, lp, sqlbuf) ;
            break ;
        case  9:                       /* Link Path Name & Key Values */
              /* Ask for the Link Path Name */
            if ( ads_getstring(0, "\nEnter LPN:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                break ;
            }
              /* Allocate the Link Path descriptor */
            if ( (lp=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) == ASE_DSC_NULL ) {
                ads_abort("\nCan't allocate the Link Path descriptor") ;
                break ;
            }
              /* Init the Link Path descriptor by the LPN */
            if ( ase_lp_initName(lp, buf) != kAsiGood ) {
                ads_printf("\nWrong LPN is entered") ;
                printAseErr(lp) ;
                break ;
            }
              /* Get the key column description */
            if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) != kAsiGood ) {
                ads_printf("\nCan't get the key column description") ;
                printAseErr(lp) ;
                break ;
            }
              /* Ask for the key values entering */
            ads_printf("\nEnter the key values") ;
            if ( pack_edit(pKey, ColQty) != kAsiGood ) {
                ads_printf("\nWrong key input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Name and Key Values */
            retCode = ase_ls_intersectLpKey(ls, buf, pKey, ColQty) ;
            break ;
        case 10:                       /* Database Object Reference & Key Values */
              /* Ask for the Database Object Reference entering */
            if ( (lp=lp_getDOR(NULL, kAsiTrue, kAsiFalse)) == ASE_DSC_NULL ) {
                break ;
            }
              /* Check the DOR */
            if ( ase_lp_getPathCode(lp) != kAseLpnCode &&
                 ase_lp_getPathCode(lp) != kAseTableCode ) {
                ads_printf("\nNot the Table Reference is entered") ;
                break ;
            }
              /* Get the description of the columns */
            if ( ase_lp_getPathCode(lp) == kAseLpnCode ) {
                  /* Get the key column description */
                if ( ase_lp_getKeyDsc(lp, &pKey, &ColQty) != kAsiGood ) {
                    ads_printf("\nCan't get the key column description") ;
                    printAseErr(lp) ;
                    break ;
                }
                ads_printf("\nEnter the key values") ;
            } else {
                  /* Get the description of the all table columns */
                ads_printf("\nEnter the row values") ;
                if ( lp_getTabCols(lp, &pKey, &ColQty) != kAsiGood ) {
                    ads_printf("\nCan't get the table column desc") ;
                    break ;
                }
                  /* Get the description of the all table columns */
                ads_printf("\nEnter the row values") ;
            }
              /* Ask for the values entering */
            if ( pack_edit(pKey, ColQty) != kAsiGood ) {
                ads_printf("\nWrong key input") ;
                break ;
            }
              /* Filter the Link Selection by the */
              /* Link Path Descriptor and Key Values */
            retCode = ase_ls_intersectLpDscKey(ls, lp, pKey, ColQty) ;
            break ;
        }
    } while(0) ;
    if ( retCode == kAsiGood ) {
        ads_printf("\nThe New Links Quantity #%ld", ase_ls_getQty(ls)) ;
    } else {
        ads_printf("\nLink Selection isn't filtered") ;
        printAseErr(ls) ;
    }
      /* Free the Link Path descriptor */
    ase_dsc_free(&lp) ;
      /* Destroy the key packet */
    asei_destroy_cdscpack(&pKey, ColQty) ;
    return retCode ;
} /* ls_filter() */

/****************************************************************************/
/*.doc ls_print(internal) */
/*+
    Prints all of the links from the Link Selection related with the
    specified Link Path.
    The Link Path descriptor may be not specified (ASE_DEC_NULL).
    In this case this function prints all the links from link selection.
    KeyBuf specifies the key buffer. If it is not NULL,
    then the key buffer already exists and the
    link selection contains the links to one LPN.
    Otherwise, this function has to get key buffers
    for each LPN. If KeyBuf is specified, lp have to have the LPN.
-*/
/****************************************************************************/
static void        
/*FCN*/ls_print(ASE_LSDSC ls, 
                    ASE_LPDSC lp, 
                    ASICOLDSC KeyBuf[], 
                    int ColQty) 
{
    ASE_LPDSC lpbuf=ASE_DSC_NULL ;   /* The Link Path buffer */
    ASICOLDSC *pKey=NULL ;           /* The key column description */
    struct resbuf *pNames=NULL ;     /* The Link Path Names */
    struct resbuf *ptr ;             /* Scanning pointer */
    int colQty ;                     /* The key columns quantity */

    do {
        if ( lp != ASE_DSC_NULL ) {
              /* Filter the links to the DOR */
            if ( ase_ls_intersectLpDsc(ls, lp) != kAsiGood ) {
                ads_printf("\nLink Selection intersecting problem") ;
                printAseErr(ls) ;
                break ;
            }
        } 
        /* Check the link selection length */
        if ( ase_ls_getQty(ls) == 0L ) {
            ads_printf("\nLink Selection is empty") ;
            printAseErr(ls) ;
            break ;
        }
        /* Get the Link Path Names */
        if ( (pNames=ase_ls_getLinkNames(ls)) == NULL ) {
            ads_printf("\nCan't get the LPN list") ;
            printAseErr(ls) ;
            break ;
        }
        if ( KeyBuf == (ASICOLDSC*)NULL ) {
            /* Prepare to print the non-homogenity links */
            if ( (lpbuf=ase_dsc_alloc(AseAppl, kAseApiLinkPath)) 
                 == ASE_DSC_NULL ) {
                ads_abort("\nCan't allocate the Link Path descriptor") ;
                break ;
            }
        }
        for ( ptr=pNames; ptr != NULL; ptr = ptr->rbnext ) {
            if ( KeyBuf != (ASICOLDSC*)NULL ) {
                ls_printLp(ls, ptr->resval.rstring, KeyBuf, ColQty) ;
            } else {
                  /* Init the link Path */
                if ( ase_lp_initName(lpbuf, ptr->resval.rstring) 
                     != kAsiGood ) {
                      ads_printf("\nWrong LPN %s is met", ptr->resval.rstring) ;
                      printAseErr(lpbuf) ;
                      break ;
                }
                  /* Get the Key buffer */
                if ( ase_lp_getKeyDsc(lpbuf, &pKey, &colQty) != kAsiGood ) {
                    ads_printf("\nCan't get the key desc for LPN %s", 
                    ptr->resval.rstring) ;
                    printAseErr(lpbuf) ;
                    break ;
                }
                  /* Print the links for the LPN */
                ls_printLp(ls, ptr->resval.rstring, pKey, colQty) ;
                asei_destroy_cdscpack(&pKey, colQty) ;
            }
        }
    } while(0) ;
    if ( pNames != NULL )
        ads_relrb(pNames) ;
    ase_dsc_free(&lpbuf) ;
} /* end of ls_print() */

/****************************************************************************/
/*.doc ls_printLp(internal) */
/*+
  Prints the homogenity links from the Link Selection, having
  the specified Link Path Name.
  The key buffer has to be specified.
-*/
/****************************************************************************/
static void        
/*FCN*/ls_printLp(ASE_LSDSC ls, 
                      const char *pName,
                      ASICOLDSC KeyBuf[],
                      int ColQty) 
{
    ASE_LSDSC lsbuf=ASE_DSC_NULL ;   /* The link selection buffer */
    ASE_LINKDSC link=ASE_DSC_NULL ;  /* The Link descriptor */
    LinkID ID ;                      /* The link identifier */
    long index ;                     /* The scanning index */
    long length ;                    /* The Link Selection length */

    do {
          /* Copy */
        if ( (lsbuf=ase_dsc_clone(ls)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't copy the link selection") ;
            printAseErr(ls) ;
            break ;
        }
          /* Filter the link selection */
        if ( ase_ls_intersectLp(lsbuf, pName) != kAsiGood ) {
            ads_printf("\nLink Selection intersecting problem") ;
            printAseErr(lsbuf) ;
            break ;
        }
          /* Check the link selection length */
        if ( (length = ase_ls_getQty(lsbuf)) == 0L ) {
            ads_printf("\nLink Selection is empty") ;
            printAseErr(lsbuf) ;
            break ;
        }
          /* Allocate the Link Descriptor */
        if ( (link=ase_dsc_alloc(AseAppl, kAseApiLink)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the Link Descriptor") ;
            break ;
        }
          /* Scan the link selection */
        for ( index=0L ; index < length ; index++ ) {
              /* Get the identifier for the specified position */
            if ( (ID=ase_ls_getId(lsbuf, index)) == LINKID_NULL ) {
                ads_printf("\nWrong Link Identifier in Link Sel") ;
                printAseErr(lsbuf) ;
                break ;
            }
              /* Init the attributes of the Link Descriptor */
            if ( ase_link_initId(link, ID) != kAsiGood ) {
                ads_printf("\nCan't get the identifier of the Link %ld", ID) ;
                printAseErr(link) ;
                break ;
            }
              /* Print the Link Data */
            link_print(link, KeyBuf, ColQty) ;
        }
    } while(0) ;
    ase_dsc_free(&link) ;
    ase_dsc_free(&lsbuf) ;
} /* end of ls_printLp() */

/****************************************************************************/
/*.doc ls_printStat(internal) */
/*+
  This function prints the Link Selection statistic,
  using the specified Link Path descriptor.
-*/
/****************************************************************************/
static void        
/*FCN*/ls_printStat(ASE_LSDSC ls, ASE_LPDSC lp) 
{
    ASE_LSDSC lsbuf=ASE_DSC_NULL ; /* Link selection buffer */
    char buf[BUFLEN] ;               /* The buffer */

    do {
          /* Get the DOR */
        ase_lp_getName(lp, buf, BUFLEN, kAsePathCode) ;
          /* Copy the original link sel */
        if ( (lsbuf=ase_dsc_clone(ls)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't copy the link selection") ;
            printAseErr(ls) ;
            break ;
        }
          /* Filter the links to the specified Link Path */
        if ( ase_ls_intersectLpDsc(lsbuf, lp) != kAsiGood ) {
            ads_printf("\nLink Selection intersecting problem") ;
            printAseErr(lsbuf) ;
            break ;
        }
        if ( ase_ls_getQty(lsbuf) == 0L ) {
            ads_printf("\nNo Links to DOR [%s]", buf) ;
            break ;
        }
          /* Statistic for All link types */
        ls_printTypeStat(lsbuf, lp, (char*)NULL, (char*)NULL, kAseUnknownLinkType) ;
          /* Statistic for Entity Links */
        ls_printTypeStat(lsbuf, lp, (char*)NULL, (char*)NULL, kAseEntityLink) ;
          /* Statistic for DA Links */
        ls_printTypeStat(lsbuf, lp, (char*)NULL, (char*)NULL, kAseDALink) ;
          /* Print the statistic for LPNs */
        ls_printLPNsStat(lsbuf) ;
          /* Print the statistic for Xref/Blocks */
        ls_printXsStat(lsbuf) ;
    } while(0) ;
    ase_dsc_free(&lsbuf) ;
} /* end of ls_printStat() */

/****************************************************************************/
/*.doc ls_printTypeStat(internal) */
/*+
  This function prints the information related with the
  specified link selection, Link Path and the type.
-*/
/****************************************************************************/
static void        
/*FCN*/ls_printTypeStat(ASE_LSDSC ls, 
                      ASE_LPDSC lp,
                      char *pName,
                      char *pXName,
                      EAseLinkType Type) 
{
   ASE_LSDSC lsbuf=ASE_DSC_NULL ;   /* The Link Selection for filtering */
   char buf[BUFLEN] ;               /* The buffer */
   ads_name ssbuf ;                 /* The entity selection buffer */
   long          Len=0L ;           /* Selection set length */

   do {
       if ( lp != ASE_DSC_NULL ) {
             /* Get the DOR */
           ase_lp_getName(lp, buf, BUFLEN, kAsePathCode) ;
       } else if ( pName != NULL ) {
           strcpy(buf, pName) ;
       } else if ( pXName != NULL ) {
           strcpy(buf, pXName) ;
       } else {
           break ;
       }
         /* Print the staticstic type */
       switch(Type) {
       case kAseEntityLink:            /* ENTITY LINK */
           ads_printf("\nEntity Links Statistic for %s [%s]", 
                 (lp!=ASE_DSC_NULL?"DOR":(pName!=NULL?"LPN":"Xref/Block")),
                 buf) ;
           break ;
       case kAseDALink:                /* DA LINK */
           ads_printf("\nDA Links Statistic for %s [%s]", 
                 (lp!=ASE_DSC_NULL?"DOR":(pName!=NULL?"LPN":"Xref/Block")),
                 buf) ;
           break ;
       case kAseUnknownLinkType:       /* ALL LINKS */
           ads_printf("\nLink Statistic for %s [%s]", 
                 (lp!=ASE_DSC_NULL?"DOR":(pName!=NULL?"LPN":"Xref/Block")),
                 buf) ;
       }
         /* Copy the original link sel */
       if ( (lsbuf=ase_dsc_clone(ls)) == ASE_DSC_NULL ) {
           ads_abort("\nCan't copy the link selection") ;
           printAseErr(ls) ;
           break ;
       }
         /* Filter the Link type */
       if ( Type != kAseUnknownLinkType ) {
           if ( ase_ls_intersectType(lsbuf, Type) != kAsiGood ) {
               ads_printf("\nLink Selection intersecting problem") ;
               printAseErr(lsbuf) ;
               break ;
           }
       }
       if ( ase_ls_getQty(lsbuf) == 0L ) {
           ads_printf("\nNo Links of the specified type") ;
       } else {
           ads_printf("\nLinks #%ld", ase_ls_getQty(lsbuf)) ;
             /* Get the entity selection */
           if ( ase_ls_getEntSel(lsbuf, ssbuf) != kAsiGood ) {
               ads_printf("\nCan't get the entity selection for Entity Links") ;
               printAseErr(lsbuf) ;
               break ;
           }
             /* Print the quantity of the entities */
           if ( ads_sslength(ssbuf, &Len) == RTNORM ) {
               ads_printf("\nEntities #%ld", Len) ;
           } else {
               ads_printf("\nWrong Entity selection name was got") ;
           }
             /* Free the entity selection */
           ads_ssfree(ssbuf) ;
       }
   } while(0) ;
   ase_dsc_free(&lsbuf) ;
} /* end of ls_printTypeStat() */

/****************************************************************************/
/*.doc ls_printLPNsStat(internal) */
/*+
  Gets the list of the LPNs for specified link selection and
  prints the links statistic for each LPN
-*/
/****************************************************************************/
static void        
/*FCN*/ls_printLPNsStat(ASE_LSDSC ls)
{
   ASE_LSDSC lsbuf=ASE_DSC_NULL ; /* Link selection buffer */
   struct resbuf *pBuf=NULL ;       /* Buffer for related names */
   struct resbuf *ptr ;             /* Scanning result buffer pointer */
     /* Get related LPNs */
   if ( (pBuf=ase_ls_getLinkNames(ls)) == NULL ) {
       ads_printf("\nNo related LPNs") ;
       return ;
   }
   for ( ptr=pBuf ; ptr != NULL ; ptr = ptr->rbnext ) {
         /* Copy the original link sel */
       if ( (lsbuf=ase_dsc_clone(ls)) == ASE_DSC_NULL ) {
           ads_abort("\nCan't copy the link selection") ;
           printAseErr(ls) ;
           break ;
       }
         /* Filter by the LPN */
       if ( ase_ls_intersectLp(lsbuf, ptr->resval.rstring) != kAsiGood ) {
           ads_printf("\nLink Selection intersecting problem") ;
           printAseErr(lsbuf) ;
           break ;
       }
         /* Print the statistic for that LPN */
       ls_printTypeStat(lsbuf, ASE_DSC_NULL, ptr->resval.rstring, 
                       (char*)NULL, kAseUnknownLinkType) ;
       ase_dsc_free(&lsbuf) ;
   }
   if ( pBuf != NULL ) {
       ads_relrb(pBuf) ;
   }
} /* end of ls_printLPNsStat() */

/****************************************************************************/
/*.doc ls_printXsStat(internal) */
/*+
  Gets the list of the Xref/Block names for specified link selection and
  prints the links statistic for each Xref/Block
-*/
/****************************************************************************/
static void        
/*FCN*/ls_printXsStat(ASE_LSDSC ls)
{
   ASE_LSDSC lsbuf=ASE_DSC_NULL ; /* Link selection buffer */
   struct resbuf *pBuf=NULL ;       /* Buffer for related names */
   struct resbuf *ptr ;             /* Scanning result buffer pointer */
     /* Get related LPNs */
   if ( (pBuf=ase_ls_getXNames(ls)) == NULL ) {
       ads_printf("\nNo related Xrefs/Blocks") ;
       return ;
   }
   for ( ptr=pBuf ; ptr != NULL ; ptr = ptr->rbnext ) {
         /* Copy the original link sel */
       if ( (lsbuf=ase_dsc_clone(ls)) == ASE_DSC_NULL ) {
           ads_abort("\nCan't copy the link selection") ;
           printAseErr(ls) ;
           break ;
       }
         /* Filter by the Xref/Block */
       if ( ase_ls_intersectXName(lsbuf, ptr->resval.rstring) != kAsiGood ) {
           ads_printf("\nLink Selection intersecting problem") ;
           printAseErr(lsbuf) ;
           break ;
       }
         /* Print the statistic for that Xref/Block */
       ls_printTypeStat(lsbuf, ASE_DSC_NULL, (char*)NULL,
                       ptr->resval.rstring, 
                       kAseUnknownLinkType) ;
       ase_dsc_free(&lsbuf) ;
   }
   if ( pBuf != NULL ) {
       ads_relrb(pBuf) ;
   }
} /* end of ls_printXsStat() */

/****************************************************************************/
/*.doc link_edit(internal) */
/*+
  Asks for the Link modification.
  After the succesfull updating, refreshes the link data
  in the specified link descriptor.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/link_edit(ASE_LINKDSC link,
                ASE_LPDSC lp, 
                ASICOLDSC Key[], 
                int ColQty) 
{
    ASE_LPDSC newlp=ASE_DSC_NULL ;        /* The new Link Path Descriptor */
    ASICOLDSC *pNewKey=(ASICOLDSC*)NULL ; /* New Key buffer */
    ASICOLDSC *pNewDAVals=(ASICOLDSC*)NULL ; /* New DA values buffer */
    ASE_LINKDSC newlink=ASE_DSC_NULL ;    /* The link buffer */
    ads_name ename ;                      /* New Entity Name */
    ads_point pt ;                         /* the point */
    char buf[BUFLEN] ;                  /* The buffer for entering */
    int DAColQty ;                        /* DA columns quantity */
    int newColQty ;                       /* New column quantity */
    int retword ;                      /* ads_getkword() returning value */
    EAsiBoolean retCode = kAsiBad ;       /* The returning flag */

      /* Make the link copy */
    if ( (newlink=ase_dsc_clone(link)) == ASE_DSC_NULL ) {
        ads_abort("\nCan't clone the Link Descriptor") ;
        return kAsiBad ;
    }
      /* Make the Link Path copy */
    if ( (newlp=ase_dsc_clone(lp)) == ASE_DSC_NULL ) {
        ads_abort("\nCan't clone the Link Path Descriptor") ;
        return kAsiBad ;
    }
      /* Make the Key Buffer copy */
    if ( (pNewKey=asei_dupl_cdscpack(Key, ColQty)) == (ASICOLDSC*)NULL ) {
        ads_abort("\nCan't clone the Key buffer") ;
        return kAsiBad ;
    }
    newColQty = ColQty ;
    do {
          /* Print the Link Data */
        link_print(newlink, pNewKey, newColQty) ;
          /*Lpn/Key/Entity/DAValues/Update/<eXit>*/
        if ( ads_initget(0, "L K E D U X") != RTNORM ) {
            break ;
        }
        retword=ads_getkword(
             "\nLpn/Key/Entity/DAValues/Update/<eXit>:", 
              buf) ;
        if ( retword != RTNORM && retword != RTNONE ) {
            break ;
        }
        if ( retword == RTNONE || buf[0] == '\0' || buf[0] == 'X' ) {
            retCode = kAsiGood ;
            break ;
        }
        switch(buf[0]) {
        case 'L':                      /* LPN */
            if ( ads_getstring(0, "\nEnter new LPN<>:", buf) != RTNORM ) {
                ads_printf("\nNo input") ;
                ase_dsc_free(&lp) ;
                break ;
            }
            /* Check the new entered LPN */
            if ( ! ase_lp_cmpName(newlp, buf, kAseLpnCode) ) {
                  /* new LPN has entered */
                if ( ase_lp_initName(newlp, buf) != kAsiGood ) {
                    ads_printf("\nWrong LPN was entered") ;
                    printAseErr(newlp) ;
                    break ;
                }
                  /* Free the old key buffer */
                asei_destroy_cdscpack(&pNewKey, newColQty) ;
                  /* Get the new Key buffer */
                if ( ase_lp_getKeyDsc(newlp, &pNewKey, &newColQty)
                     != kAsiGood ) {
                    ads_printf("\nCan't get the Key Description") ;
                    printAseErr(newlp) ;
                    break ;
                }
                  /* Update the new LPN */
                if ( ase_link_setName(newlink, buf) != kAsiGood ) {
                    ads_printf("\nCan't update the LPN") ;
                    printAseErr(newlink) ;
                    break ;
                }
            }
              /* Ask for the new Key column values now */
            if ( pack_edit(pNewKey, newColQty) != kAsiGood ) {
                ads_printf("\nWrong Key input") ;
                break ;
            }
              /* Update the new Key */
            if ( ase_link_setKey(newlink, pNewKey, newColQty) 
                 != kAsiGood ) {
                ads_printf("\nCan't update the key") ;
                printAseErr(newlink) ;
                break ;
            }
            break ;
        case 'K':                      /* KEY */
              /* Ask for the new Key column values now */
            if ( pack_edit(pNewKey, newColQty) != kAsiGood ) {
                ads_printf("\nWrong Key input") ;
                break ;
            }
            if ( ase_link_setKey(newlink, pNewKey, newColQty) 
                 != kAsiGood ) {
                ads_printf("\nCan't update the key") ;
                printAseErr(newlink) ;
                break ;
            }
            break ;
        case 'E':                      /* ENTITY */
              /* Ask for the entity name */
            if ( ads_entsel("\nSelect object:", ename, pt) != RTNORM ) {
                ads_printf("\nWrong entity name input") ;
                break ;
            }
              /* Set the new Entity Name */
            if ( ase_link_setEntity(newlink, ename) != kAsiGood ) {
                ads_printf("\nCan't update the Entity") ;
                printAseErr(newlink) ;
                break ;
            }
            break ;
        case 'D':                      /* DA VALUES */
            if ( ase_link_getType(newlink) != kAseDALink ) {
                ads_printf("\nNo DA Link") ;
                break ;
            }
              /* Get the DA columns */
            if ( ase_link_getDACols(newlink, &pNewDAVals, &DAColQty) 
                 != kAsiGood ) {
                ads_printf("\nCan't get the DA columns") ;
                printAseErr(newlink) ;
                break ;
            }
              /* Ask for the new DA values entering */
            if ( pack_edit(pNewDAVals, DAColQty) != kAsiGood ) {
                ads_printf("\nWrong DA Columns input") ;
                break ;
            }
              /* Update the new DA values */
            if ( ase_link_setDAValues(newlink, pNewDAVals, DAColQty) 
                 != kAsiGood ) {
                ads_printf("\nCan't update the DA Column values") ;
                printAseErr(newlink) ;
                break ;
            }
            break ;
        case 'U':                      /* UPDATE */
              /* Real link updating */
            if ( ase_link_update(newlink) != kAsiGood ) {
                ads_printf("\nCan't update the link") ;
                printAseErr(newlink) ;
                break ;
            }
              /* Refresh the input Link Descriptor */
            if ( ase_dsc_copyFrom(link, newlink) != kAsiGood ) {
                ads_printf("\nCan't copy the Link Descriptor") ;
                break ;
            }
            break ;
        }
    } while(1) ;
    asei_destroy_cdscpack(&pNewKey, newColQty) ;
    asei_destroy_cdscpack(&pNewDAVals, DAColQty) ;
    ase_dsc_free(&newlink) ;
    ase_dsc_free(&newlp) ;
    return retCode ;
} /* end of link_edit() */

/****************************************************************************/
/*.doc link_entMake(internal) */
/*+
  Makes an Entity link to the current row of the specified cursor 
  in accordance with the Link Path.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/link_entMake(
                    ASICURSOR csr,      /* The cursor descriptor */
                    ASE_LPDSC lp        /* Link Path Descriptor */
                    ) 
{
    ASE_LINKDSC link=ASE_DSC_NULL ;     /* The link descriptor */
    ASICOLDSC *pKeyVal=(ASICOLDSC*)NULL ;  /* The key values */
    ads_point pt ;                         /* the point */
    ads_name ename ;                       /* Entity Name to be linked */
    char LPN[BUFLEN] ;                   /* The Link Path Name */
    int ColQty ;                           /* The key values quantity */
    EAsiBoolean retCode=kAsiBad ;          /* The returning code */

    do {
          /* Allocate the Link Descriptor */
        if ( (link=ase_dsc_alloc(AseAppl, kAseApiLink)) == ASE_DSC_NULL) {
            ads_abort("\nCan't allocate Link Descriptor") ;
            break ;
        }
          /* Test the Link Type Initialization function */
        if ( ase_link_initType(link, kAseEntityLink) != kAsiGood ) {
            ads_printf("\nCan't initialize an Entity Link Descriptor") ;
            printAseErr(link) ;
            break ;
        }
          /* Get the LPN */
        if ( ase_lp_getName(lp, LPN, BUFLEN, kAseLpnCode) != kAsiGood ) {
            ads_printf("\nCan't get the LPN") ;
            break ;
        }
          /* Get the key column description */
        if ( ase_lp_getKeyDsc(lp, &pKeyVal, &ColQty) != kAsiGood ) {
            ads_printf("\nCan't get the key column description") ;
            break ;
        }
          /* Get the key values */
        if ( csr_getVals(csr, &pKeyVal, &ColQty) != kAsiGood ) {
            ads_printf("\nCan't extract the key values") ;
            break ;
        }
          /* Ask for the entity name */
        if ( ads_entsel("\nSelect object:", ename, pt) != RTNORM ) {
            ads_printf("\nWrong entity name input") ;
            break ;
        }
          /* Init the Entity Link */
        if ( ase_link_initEntityLink(link, LPN, 
                                     pKeyVal, ColQty, ename) != kAsiGood ) {
            ads_printf("\nCan't initilize the Entity Link") ;
            printAseErr(link) ;
            break ;
        }
          /* Create the initialized link */
        if ( ase_link_create(link) != kAsiGood ) {
            ads_printf("\nCan't create the link") ;    
            printAseErr(link) ;
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&link) ;
    asei_destroy_cdscpack(&pKeyVal, ColQty) ;
    return retCode ;
} /* end of link_entMake() */

/****************************************************************************/
/*.doc link_daMake(internal) */
/*+
  Makes an DA link to the current row of the specified cursor 
  in accordance with the Link Path.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/link_daMake(
                   ASICURSOR csr,      /* The cursor descriptor */
                   ASE_LPDSC lp        /* Link Path Descriptor */
                  )
{
    ASE_LINKDSC link=ASE_DSC_NULL ;     /* The link descriptor */
    ASICOLDSC *pKeyVal=(ASICOLDSC*)NULL ;  /* The key values */
    ASICOLDSC *pDACols=(ASICOLDSC*)NULL ;  /* The DA columns */
    ASICOLDSC *pTabCols=(ASICOLDSC*)NULL;  /* The table columns */
    ASICOLDSC col ;                        /* For cursor column getting */
    ads_point point ;         /* The DA insertion point */
    ads_real  angle ;         /* The DA rotation angle */
    ads_real  high ;          /* The DA text high */
    struct resbuf *pParms=NULL ;           /* DA Entity parameters */
    char LPN[BUFLEN] ;                   /* The Link Path Name */
    int ColQty ;                           /* The key values quantity */
    int DAColQty ;                         /* DA columns */
    int TabColQty ;                        /* The table columns */
    int index ;                            /* scanning index */
    EAsiBoolean retCode=kAsiBad ;          /* The returning code */

    do {
          /* Allocate the Link Descriptor */
        if ( (link=ase_dsc_alloc(AseAppl, kAseApiLink)) == ASE_DSC_NULL) {
            ads_abort("\nCan't allocate Link Descriptor") ;
            break ;
        }
          /* Test the Link Type Initialization function */
        if ( ase_link_initType(link, kAseDALink) != kAsiGood ) {
            ads_printf("\nCan't initialize an DA Link Descriptor") ;
            printAseErr(link) ;
            break ;
        }
          /* Get the LPN */
        if ( ase_lp_getName(lp, LPN, BUFLEN, kAseLpnCode) != kAsiGood ) {
            ads_printf("\nCan't get the LPN") ;
            break ;
        }
          /* Get the key column description */
        if ( ase_lp_getKeyDsc(lp, &pKeyVal, &ColQty) != kAsiGood ) {
            ads_printf("\nCan't get the key column description") ;
            break ;
        }
          /* Get the key values */
        if ( csr_getVals(csr, &pKeyVal, &ColQty) != kAsiGood ) {
            ads_printf("\nCan't extract the key values") ;
            break ;
        }
          /* Get the table columns */
        TabColQty = asi_colcount(csr) ;
          /* Allocate the description of table columns */
        if ( (pTabCols=asei_constr_cdscpack(TabColQty)) 
            == (ASICOLDSC*)NULL ) {
            ads_abort("\nCan't allocate the column packet") ;
            break ;
        }
          /* Copy the column description */
        for ( index=0 ; index < TabColQty ; index++ ) {
              /* Get the column description */
            if ( asi_cds(csr, index, &col) != kAsiGood ) {
                ads_printf("\nCan't get the column description") ;
                break ;
            }
              /* Copy the description */
            if ( (pTabCols[index]=asei_dupl_cdsc(col)) == 0L ) {
                ads_abort("\nCan't duplicate the column description") ;
                break ;
            }
        }
          /* Check the exit condition */
        if ( index < TabColQty ) {
            break ;
        }
          /* Ask for the DA column description */
        if ( pack_getCols(pTabCols, TabColQty,
                       &pDACols, &DAColQty) != kAsiGood ) {
            break ;
        }
          /* Ask for the DA column values */
        if ( csr_getVals(csr, &pDACols, &DAColQty) != kAsiGood ) {
            ads_printf("\nCan't extract the DA values") ;
            break ;
        }
          /* Ask for the insertion pointe*/
        if ( ads_getpoint(NULL, "\nDA insertion point:", point) != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
          /* Ask for the text high */
        if ( ads_getdist(point, "\nDA text high:", &high) != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
          /* Ask for the angle */
        if ( ads_getangle(point, "\nDA rotation angle:", &angle) != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
          /* Build the parameters list */
        if ( (pParms=ads_buildlist(10, point, 
                                   40, high, 
                                   50, angle, 
                                   RTNONE)) == NULL ) {
            ads_abort("\nCan't build the resbuf list") ;
            break ;
        }
          /* Init the DA link */
        if ( ase_link_initDALink(link, LPN,
                                 pKeyVal, ColQty,
                                 pDACols, DAColQty,
                                 pParms) != kAsiGood ) {
            ads_printf("\nCan't initialize the DA link") ;
            printAseErr(link) ;
            break ;
        }
          /* Create the already initialized DA link */
        if ( ase_link_create(link) != kAsiGood ) {
            ads_printf("\nCan't create the DA link") ;
            printAseErr(link) ;
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( pParms != NULL ) {
        ads_relrb(pParms) ;
    }
    ase_dsc_free(&link) ;
    asei_destroy_cdscpack(&pKeyVal, ColQty) ;
    asei_destroy_cdscpack(&pTabCols, DAColQty) ;
    asei_destroy_cdscpack(&pDACols, TabColQty) ;
    return retCode ;
} /* end of link_daMake() */

/****************************************************************************/
/*.doc link_print(internal) */
/*+
    Prints the data of the specified Link.
    This function uses the specified key column
    description as the buffer for getting the key values
    of the link. If Key is (ASICOLDSC*)NULL, then this 
    function tries to get the it allocating the 
    correspondent Link Path.
-*/
/****************************************************************************/
static void        
/*FCN*/link_print(
                 ASE_LINKDSC link,    /* The link descriptor */
                 ASICOLDSC Key[],     /* The key buffer */
                 int ColQty           /* The key columns quantity */
                ) 
{
    ASE_LPDSC   lp=ASE_DSC_NULL ; /* Link Path Descriptor */
    ASICOLDSC  *pKey=NULL ;       /* The key buffer */
    ASICOLDSC  *pDACols=NULL ;    /* The DA column buffer */
    char       *pName=NULL;       /* The LPN buffer pointer */
    ads_name    ename ;           /* The entity name */
    int         colNum ;          /* The key columns quantity */
    int         DAColNum ;        /* The DA columns quantity */
    int         len ;             /* The LPN size */       

    do {
        /* Print the link type */
        if ( ase_link_getType(link) == kAseEntityLink ) {
            ads_printf("\nEntity Link") ;
        } else if ( ase_link_getType(link) == kAseDALink ) {
            ads_printf("\nDisplayble Attribute") ;
        } else {
            ads_printf("\nUnknown Link Type") ;
        }
        /* Print the link identifier */
        ads_printf("  ID: %ld", ase_link_getId(link)) ;
          /* Get the Link Path Name size */
        if ( (len=ase_link_getNameSize(link)) <= 0 ) {
            ads_printf("\nWrong LPN size") ;
            printAseErr(link) ;
            break ;
        }
          /* Allocate LPN buffer */
        if ( (pName=(char*)calloc(1, len)) == NULL ) {
            ads_abort("\nNo memory") ;
            break ;
        }
          /* Get the LPN */
        if ( ase_link_getName(link, pName, len) != kAsiGood ) {
            ads_printf("\nCan't get th link path name") ;
            printAseErr(link) ;
            break ;
        }
        ads_printf("\nLPN: %s", pName) ;
          /* Check the key buffer */
        if ( Key == (ASICOLDSC*)NULL ) {
              /* Get the Link Path Name */
            if ( (lp=ase_dsc_alloc(AseAppl, kAseApiLinkPath))
                 == ASE_DSC_NULL ) {
                ads_abort("Can't allocate the Link Path descriptor") ;
                break ;
            }
              /* Init the Link Path descriptor by the LPN */
            if ( ase_lp_initName(lp, pName) != kAsiGood ) {
                ads_printf("\nInvalid LPN") ;
                printAseErr(lp) ;
                break ;
            }
              /* Get the key buffer */
            if ( ase_lp_getKeyDsc(lp, &pKey, &colNum) != kAsiGood ) {
                ads_printf("\nCan't get the Key Description") ;
                printAseErr(lp) ;
                break ;
            }
        } else {
            /* The key buffer is specified */
            pKey = Key ;
            colNum = ColQty ;
        }
          /* Get the link key value */
        if ( ase_link_getKey(link, pKey, colNum) != kAsiGood ) {
            ads_printf("\nCan't get the Key Values") ;
            printAseErr(link) ;
            break ;
        }
          /* Print the key values */
        pack_print(pKey, colNum) ;
          /* Get the entity name */
        if ( ase_link_getEntity(link, ename) != kAsiGood ) {
            ads_printf("\nCan't get the Entity Name") ;
            printAseErr(link) ;
            break ;
        }
        ads_printf("\nEntity [%ld, %ld]", ename[0], ename[1]) ;
          /* Get the Xref/Block name */
        if ( pName != NULL )
            free (pName) ;
        if ( (pName=(char*)calloc(1, 33)) == NULL ) {
            ads_abort("\nNo Memory") ;
            break ;
        }
          /* Get the Xref/Block name */
        if ( ase_link_getXName(link, pName, 33) != kAsiGood ) {
            ads_printf("\nCan't get the Xref/Block name") ;
            printAseErr(link) ;
            break ;
        }
          /* Print Xref/Block name */
        if ( *pName != '\0' ) {
            ads_printf("\nXref/Block: %s", pName) ;
        }
        if ( ase_link_isUpdatable(link) == kAsiTrue ) {
            ads_printf("\nLink is updatable") ;
        } else {
            ads_printf("\nLink isn't updatable") ;
            /* Clear the non-updatability reasons data */
            ase_dsc_errClear(link) ;
        }
          /* Process DA Link */
        if ( ase_link_getType(link) == kAseDALink ) {
            /* Get the DA column names for the DA link */
            if ( ase_link_getDACols(link, &pDACols, &DAColNum) != kAsiGood ) {
                ads_printf("\nCan't get the DA column names") ;
                printAseErr(link) ;
                break ;
            }
              /* Print the DA column values */
            pack_printVals(pDACols, DAColNum) ;
        }
    } while(0) ;
      /* Free LPN buffer */
    if ( pName != NULL ) {
        free(pName) ;
    }
    ase_dsc_free(&lp) ;
    if ( Key == (ASICOLDSC*)NULL ) {
        asei_destroy_cdscpack(&pKey, colNum) ;
    }
    asei_destroy_cdscpack(&pDACols, DAColNum) ;
} /* end of link_print() */

/****************************************************************************/
/*.doc pack_print(internal) */
/*+
  Prints the full column descriptions of the specified packet
-*/
/****************************************************************************/
static void        
/*FCN*/pack_print(ASICOLDSC Pack[],
                 int ColQty) 
{
    ASIDATADSC    datadsc=0L;
    ASIIDENT ident ;      /* Column identifier */
    char buf[BUFLEN] ;  /* The buffer for printing values */
    int index ;           /* The row column scanning index */
    EAsiBoolean isNull ;  /* Null value indicator */

    for ( index = 0 ; index < ColQty ; index++ ) {
        if ( asi_cdsc_name(Pack[index], &ident) != kAsiGood ) {
            ads_printf("\nCan't get the column identifier") ;
        }
        /* Get the ident name */
        if ( asi_get_ident(ident, buf, BUFLEN) == NULL ) {
            ads_printf("\nCan't get the identifier name") ;
            asi_destroy_ident(&ident) ;
            break ;
        }
        asi_destroy_ident(&ident) ;
        /* Print the ident name */
        ads_printf("\n%s, ", buf) ;
          /* Print column type */
        if (asi_cdsc_ddsc (Pack[index], &datadsc) == kAsiGood) {
            ads_printf(" %s : ", asi_ddsc_sqltype (datadsc, buf, 256));
            asi_destroy_ddsc (&datadsc);
        }
        asei_cdsc_rtype(Pack[index], &isNull)  ;
        if ( isNull == kAsiTrue ) {
            /* Null value */
            buf[0] = '.' ;
            buf[1] = '\0' ;
        } else {
            if ( asei_cdsc_getstr(Pack[index], buf, BUFLEN) != kAsiGood ) {
                ads_printf("\nCan't get the value") ;
                break ;
            }
        }
        ads_printf("%s", buf) ;
    }
} /* end of pack_print() */

/****************************************************************************/
/*.doc pack_printCols(internal) */
/*+
  Prints the column descriptions of the specified packet
-*/
/****************************************************************************/
static void        
/*FCN*/pack_printCols(ASICOLDSC Pack[],
                    int ColQty) 
{
    int index ;
    for (index=0 ; index < ColQty && Pack[index] != 0L ; index++ ) {
        ads_printf("\n") ;
        printColDsc(Pack[index]) ;
    }
} /* end of pack_printCols() */

/****************************************************************************/
/*.doc pack_printVals(internal) */
/*+
    This function prints the values of the specifeid packet
-*/
/****************************************************************************/
static void        
/*FCN*/pack_printVals(ASICOLDSC Pack[], int ColQty) 
{
    ASIIDENT ident ;      /* Column identifier */
    char buf[BUFLEN] ;  /* The buffer for printing values */
    int index ;           /* The row column scanning index */
    EAsiBoolean isNull ;  /* Null value indicator */

    for ( index = 0 ; index < ColQty ; index++ ) {
        if ( asi_cdsc_name(Pack[index], &ident) != kAsiGood ) {
            ads_printf("\nCan't get the column identifier") ;
        }
        /* Get the ident name */
        if ( asi_get_ident(ident, buf, BUFLEN) == NULL ) {
            ads_printf("\nCan't get the identifier name") ;
            asi_destroy_ident(&ident) ;
            break ;
        }
        asi_destroy_ident(&ident) ;
        /* Print the ident name */
        ads_printf("\n%s : ", buf) ;
        asei_cdsc_rtype(Pack[index], &isNull)  ;
        if ( isNull == kAsiTrue ) {
            /* Null value */
            buf[0] = '.' ;
            buf[1] = '\0' ;
        } else {
            if ( asei_cdsc_getstr(Pack[index], buf, BUFLEN) != kAsiGood ) {
                ads_printf("\nCan't get the value") ;
                break ;
            }
        }
        ads_printf("%s", buf) ;
    }
} /* end of pack_printVals() */

/****************************************************************************/
/*.doc pack_edit(internal) */
/*+
    This function edits the values of the specifeid packet
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/pack_edit(ASICOLDSC Pack[], int ColQty) 
{
    ASIIDENT ident ;      /* Column identifier */
    char buf[BUFLEN] ;  /* The buffer for printing values */
    int index ;           /* The row column scanning index */
    EAsiBoolean isNull ;  /* Null value indicator */

    for ( index = 0 ; index < ColQty ; index++ ) {
        if ( asi_cdsc_name(Pack[index], &ident) != kAsiGood ) {
            ads_printf("\nCan't get the column identifier") ;
        }
        /* Get the ident name */
        if ( asi_get_ident(ident, buf, BUFLEN) == NULL ) {
            ads_printf("\nCan't get the identifier name") ;
            asi_destroy_ident(&ident) ;
            break ;
        }
        asi_destroy_ident(&ident) ;
        /* Print the ident name */
        ads_printf("\n%s <", buf) ;
        asei_cdsc_rtype(Pack[index], &isNull)  ;
        if ( isNull == kAsiTrue ) {
            /* Null value */
            buf[0] = '.' ;
            buf[1] = '\0' ;
        } else {
            if ( asei_cdsc_getstr(Pack[index], buf, BUFLEN) != kAsiGood ) {
                ads_printf("\nCan't get the value") ;
                break ;
            }
        }
        ads_printf("%s", buf) ;
        if ( ads_getstring(0, "> : ", buf) != RTNORM ) {
            ads_printf("\nNo input") ;
            break ;
        }
        if ( buf[0] == '.' ) {
            if ( asei_cdsc_setnull(Pack[index]) != kAsiGood ) {
                ads_printf("\nCan't nullify the value") ;
                break ;
            }
        } else if ( buf[0] != '\0' ) {
            if ( asei_cdsc_setstr(Pack[index], buf) != kAsiGood ) {
                ads_printf("\nNon-appropriate value is entered") ;
                break ;
            }
        }
    }
    if ( index < ColQty ) {
        return kAsiBad ;
    }
    return kAsiGood ;
} /* end of pack_edit() */

/****************************************************************************/
/*.doc pack_getCols(internal) */
/*+
  Printf the desc of the packet columns and asks for the
  column names entering.
  The ColList, ColQty have to specify the base columns description.
  The selected column description is retreived in the
  pCols, pColQty arguments.
  Returns kAsiBad if something is wrong or if no one
  column was selected.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/pack_getCols(ASICOLDSC ColList[],
                 int ColQty, 
                 ASICOLDSC *pCols[],
                 int *pColQty) 
{
    ASICOLDSC *pRetdsc = NULL ;     /* The returning columns packet */
    ASIIDENT newident=0L ;          /* New Column identifier */
    ASIIDENT ident=0L ;             /* Existing column identifier */        
    ASICOLDSC coldsc=0L ;           /* Column description */
    char buf[BUFLEN] ;              /* The buffer for dialogue asking */
    int RetQty=0 ;                  /* The returning columns quantity */
    int i ;

      /* Allocate the pointers array */
    if ( (pRetdsc=asei_constr_cdscpack(ColQty)) == (ASICOLDSC*)NULL ||
         asi_constr_ident(&newident) != kAsiGood ||
         asi_constr_ident(&ident) != kAsiGood ) {
        ads_abort("\nNo memory") ;
        return kAsiBad ;
    }
    while(1) {
        ads_printf("\nSelected Columns:") ;
        if ( RetQty > 0 ) {
              /* Print the key columns */
            pack_printCols(pRetdsc, RetQty) ;
        } else {
            ads_printf("\nNo") ;
        }
        if ( ads_getstring(0, "\nEnter the column name"
                              "or <?> for the available names: ", 
                              buf) != RTNORM ) {
            ads_printf("\nNo input") ;
            continue ;
        }
        if ( buf[0] == '\0' ) {
            break ;
        }
        if ( buf[0] == '?' ) {
              /* Print the table column */
            pack_printCols(ColList, ColQty) ;
            continue ;
        } 
          /* Initialize the identifier */
        if ( asei_ident_init(newident, buf) != kAsiGood ) {
            ads_printf("\nWrong column name") ;
            continue ;
        }
          /* Find the correspondent column description */
        for ( i=0 ; i < ColQty ; i++ ) {
              /* Get the ident of the available column */
            if ( asi_cdsc_name(ColList[i], &ident) == kAsiGood ) {
                if ( asei_ident_cmp(newident, ident) ) {
                    break ;
                }
            }
        }
        if ( i >= ColQty ) {
            ads_printf("\nNon-available column name") ;
            continue ;
        }
          /* Duplicate it and add to the Key dsc array */
        pRetdsc[RetQty] = asei_dupl_cdsc(ColList[i]) ;
        RetQty++ ;
        
          /* Check the top limit */
        if ( RetQty >= ColQty ) {
            ads_printf("\nThe max column quantity is exceeded") ;
            break ;
        }
    }
    asi_destroy_ident(&ident) ;
    asi_destroy_ident(&newident) ;
    if ( RetQty ) {
        *pCols = pRetdsc ;
        *pColQty = RetQty ;
        return kAsiGood ;
    } else {
        asei_destroy_cdscpack(&pRetdsc, ColQty) ;
        return kAsiBad ;
    }
}  /* end of pack_getCols() */

/****************************************************************************/
/*.doc connect(internal) */
/*+
  This function asks for the user name & password
  and connects application to the environment, which name has to
  be specified in the Link Path descriptor.
-*/
/****************************************************************************/
static EAsiBoolean
/*FCN*/connect(ASE_LPDSC lp) 
{
    EAsiBoolean retCode=kAsiBad ;   /* The error sign */
    char envbuf [BUFLEN] ;          /* Env name */
    char usrbuf [BUFLEN] ;          /* user name */
    char pswbuf [BUFLEN] ;          /* password */

    do {
        if ( isConnected(lp) == kAsiTrue ) {
                /* The Environment is already connected */
              retCode = kAsiGood ;
              break ;
        }
          /* Disconnect from the another Environment */
        disconnect() ;
          /* Get the Env Name */
        ase_lp_getName(lp, envbuf, BUFLEN, kAseEnvCode) ;
        ads_printf("\nEnvironment %s", envbuf) ;
        /* Check the Environment */
        if ( envbuf[0] == '\0' ) {
            ads_printf("\nEnvironment isn't specified - no connections") ;
            retCode = kAsiGood ;
            break ;
        }
        ads_getstring(0, "\nUsername:", usrbuf) ;
        ads_getstring(0, "\nPassword:", pswbuf) ;
          /* Construct the session */
        if ( asi_constr_session  (&AsiSes, AsiAppl) != kAsiGood ) {
            ads_printf("\nCan't construct ASI session desc") ;
            break ;
        }
          /* Connect to the Env */
        if ( asi_connect (AsiSes, envbuf, usrbuf, pswbuf) != kAsiGood ) {
            ads_printf("\nCan't connect") ;
            break ;
        }
        if ( (AseEnv=ase_dsc_clone(lp)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't clone Link Path descriptor") ;
            break ;
        }
        retCode = kAsiGood ;
    } while(0) ;
    if ( retCode != kAsiGood ) {
        asi_destroy_session(&AsiSes, AsiAppl) ;
        ase_dsc_free(&AseEnv) ;
    }
    return retCode ;
} /* end of connect() */

/****************************************************************************/
/*.doc connectAse(internal) */
/*+
  Connects ASE to the environment, which name has to
  be specified in the Link Path descriptor.
  Returns kAsiGood in the case of success, kAsiBad otherwise.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/connectAse(ASE_LPDSC lp) 
{
    struct resbuf *pParms=NULL ;    /* The calling parameters list */
    char envbuf[BUFLEN] ;           /* The buffer for Env name */
    char usrbuf [BUFLEN] ;          /* user name */
    char pswbuf [BUFLEN] ;          /* password */
    EAsiBoolean retCode=kAsiBad ;   /* The returning code */

    do {
          /* Check, whether or not ASE is connected to Env */
        if ( ase_lp_getStatus(lp) & ASE_DO_CON ) {
            retCode = kAsiGood ;     /* connection exists */
            break ;
        }
          /* Get the Env name */
        if ( ase_lp_getName(lp, envbuf, BUFLEN, kAseEnvCode) != kAsiGood ) {
            ads_printf("\nCan't get the Env name") ;
            printAseErr(lp) ; 
            break ;
        }
        ads_printf("\nConnecting ASE to environment %s", envbuf) ;
        if ( envbuf[0] == '\0' ) {
            retCode = kAsiGood ;     /* don't need connection */
            ads_printf("\nEnvironment name isn't specified") ;
            break ;
        }
        ads_getstring(0, "\nUsername:", usrbuf) ;
        ads_getstring(0, "\nPassword:", pswbuf) ;
          /* Build the calling parameters list */
        if ( (pParms=
              ads_buildlist(RTSTR, "E",
                            RTSTR, envbuf,
                            RTSTR, "O",
                            RTSTR, "C",
                            RTSTR, usrbuf,
                            RTSTR, pswbuf,
                            RTSTR, "",
                            RTSTR, "",
                            RTNONE)) == NULL ) {
            ads_abort("\nCan't build resbuf") ;
            break ;
        }
          /* Call ASE */
        if ( callCmd("_ASEADMIN", pParms)!= RTNORM ) {
            ads_printf("\nError in call of ASEADMIN command") ;
              /* Print the global ASE error */
            asesmp_err() ;
            break ;
        }
          /* Print the global ASE error */
        asesmp_err() ;
          /* Check whether ASE has connected to Env indeed */
        if ( ase_lp_getStatus(lp) & ASE_DO_CON ) {
            retCode = kAsiGood ;
        } else {
            ads_printf("\nError in connecting ASE to environment %s", envbuf) ;
        }
    } while(0) ;
    if ( pParms != NULL ) {
        ads_relrb(pParms) ;
    }
    return retCode ;
} /* end of connectAse() */

/****************************************************************************/
/*.doc getSession(internal) */
/*+
    Returns the global connected ASI session descriptor
-*/
/****************************************************************************/
static ASISESSION  
/*FCN*/getSession() 
{
    return AsiSes ;
} /* end of getSession() */

/****************************************************************************/
/*.doc isConnected(internal) */
/*+
    This function checks, whether the Environment,
    specified in the Link Path descriptor, is connected.
    The global variable AsiSes is responsible for the global
    connection support. AseEnv global variable is responsible
    for the keeping the connected Environment name.
    If the lp == ASE_DSC_NULL, then this function
    gets whether or not the global environment is connected.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/isConnected(ASE_LPDSC lp) 
{
    if ( lp == ASE_DSC_NULL ) {
        if ( AsiSes != 0L ) {
            return kAsiTrue ;
        }
    } else {
        if ( AsiSes != 0L &&
             AseEnv != ASE_DSC_NULL && 
             ase_lp_cmpDscName(AseEnv, lp, kAseEnvCode) ) {
            return kAsiTrue ;
        }
    }
    return kAsiFalse ;
} /* end of isConnected() */

/****************************************************************************/
/*.doc disconnect(internal) */
/*+
  This function disconnects the from connected Environment
-*/
/****************************************************************************/
static void 
/*FCN*/disconnect() 
{
    if ( isConnected(ASE_DSC_NULL) == kAsiTrue ) {
        ase_dsc_free(&AseEnv) ;
        asi_destroy_session(&AsiSes, AsiAppl) ;
    }
} /* end of disconnect() */

/****************************************************************************/
/*.doc printAseErr(internal) */
/*+
    This function prints the error data for the given
    ASE descriptor
-*/
/****************************************************************************/
static void                               
/*FCN*/printAseErr (ASE_DSC dsc) 
{
    char buf[BUFLEN] ;/* The error message buffer */
    char *ptr ;         /* The Diagnostic parameter name pointer */
    int parcode ;       /* The diagnostic parameter code */
    int isstr ;         /* The diagnostic parameter type */
    int intpar ;        /* Integer parameter value */

    int index ;         /* Error index */
    int pindex ;        /* Error parameters index */

    if ( ase_dsc_errQty(dsc) ) {
        ads_printf("\nASE Errors #%d", ase_dsc_errQty(dsc)) ;
    }
    for ( index=0 ; index < ase_dsc_errQty(dsc) ; index++ ) {
        ads_printf("\nError N%d\n----------", index) ;
        ads_printf("\nDescription Code: %d", ase_dsc_errDsc(dsc, index)) ;
        ads_printf("\nCode: %d", ase_dsc_errCode(dsc, index)) ;
          // Get the error message
        ase_dsc_errMsg(dsc, index, buf, BUFLEN) ;
        ads_printf("\nMessage: %s", buf) ;
          /* Scan all of the diagnostic parameters(ASE & ASI), */
          /* that ASE supports */
        ads_printf("\nDiagnostic Parameters are:") ;
        for ( pindex=0 ; 
              (ptr=(char*)ase_dsc_errDiagParNameCode(dsc, pindex, 
                                            &parcode, &isstr)) != NULL ;
              pindex++ ) {
            /* Get the parameter values */
            if ( isstr ) {
                /* Get the string parameter value */
                if ( ase_dsc_errDiagParStr(dsc, index, parcode, buf, BUFLEN) 
                     == kAsiGood ) {
                    ads_printf("\n%s: [%s]", ptr, buf) ;
                }
            } else {
                /* Get the integer parameter value */
                if ( ase_dsc_errDiagParInt(dsc, index, parcode, &intpar) ) {
                    ads_printf("\n%s: [%d]", ptr, intpar) ;
                }
            }
        }
    }
} /* end of printAseErr() */

/****************************************************************************/
/*.doc printAsiErr(internal) */
/*+
    Gets the errors from the specified ASI handle, put it into the
    AseAppl global descriptor and prints on the screen.
    Clear the descriptor then.
-*/
/****************************************************************************/
static void 
/*FCN*/printAsiErr(ASIHANDLE handle)
{
    if ( handle != 0L && ase_dsc_errInitAsi(AseAppl, handle) == kAsiGood ) {
        printAseErr(AseAppl) ;    
        ase_dsc_errClear(AseAppl) ;
    }
} /* printAsiErr() */

/****************************************************************************/
/*.doc testDsc(internal) */
/*+
  This function demonstrates the functions processing the
  general ASE descriptors. Returns kAsiBad if something is wrong.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/testDsc(ASE_DSC dsc) 
{
    ASE_DSC forCopy=ASE_DSC_NULL ;   /* To test ase_dsc_copyFrom() */
    ASE_DSC forClone=ASE_DSC_NULL ;  /* To test ase_dsc_clone() */
    EAsiBoolean retCode=kAsiBad ;    /* The returning code */
    do {
        if ( dsc == ASE_DSC_NULL ) {
            break ;
        }
          /* Check the descriptor validity */
        if ( ase_dsc_isInit(dsc) != kAsiTrue ) {
            switch(ase_dsc_isA(dsc)) {
            case kAseApiAppl:          /* Application descriptor */
               ads_printf("\nTest:: interface to ASE isn't established") ;
               break ;
            case kAseApiLinkPath:      /* Link Path descriptor */
               ads_printf("\nTest:: Link Path is invalid") ;
               break ;
            case kAseApiLink:          /* Link descriptor */
               ads_printf("\nTest:: Link is invalid") ;
               break ;
            case kAseApiLinkSel:       /* Link Selection descriptor */
               ads_printf("\nTest:: Link Selection isn't initialized") ;
               break ;
            }
            break ;
        }
          /* Clone the descriptor */
        if ( (forClone=ase_dsc_clone(dsc)) == ASE_DSC_NULL ) {
            ads_abort("\nCan't clone the descriptor") ;
            printAseErr(dsc) ;
            break ;
        }
          /* Check the validity of the cloned descriptor */
        if ( ase_dsc_isInit(forClone) != kAsiGood ) {
            break ;
        }
          /* Allocate the descriptor of the same type */
        if ( (forCopy=ase_dsc_alloc(AseAppl, ase_dsc_isA(dsc))) 
             == ASE_DSC_NULL ) {
            ads_abort("\nCan't allocate the descriptor") ;
            break ;
        }
          /* Check the allocated descriptor in accordance with the spec */
        if ( ase_dsc_isInit(forCopy) != kAsiGood ) {
            if ( ase_dsc_isA(dsc) == kAseApiLinkPath ) {
               ads_printf("\nTest:: Link Path is invalid") ;
               break ;
            } else if ( ase_dsc_isA(dsc) == kAseApiLink) {
               ads_printf("\nTest:: Link is invalid") ;
               break ;
            }
        }
          /* Execute the default init */
        if ( ase_dsc_init(forCopy) != kAsiGood ) {
            ads_printf("\nCan't execute the default init") ;
            printAseErr(forCopy) ;
            break ;
        }
          /* Check the validity now */
        if ( ase_dsc_isInit(forCopy) != kAsiGood ) {
           ads_printf("\nVoid descriptor is invalid") ;
           printAseErr(forCopy) ;
           break ;
        }
          /* Copy descripor data */
        if ( ase_dsc_copyFrom(forCopy, dsc) != kAsiGood ) {
            ads_printf("\nCan't copy the descriptor") ;
            printAseErr(dsc) ;
            break ;
        }
          /* Compare the descriptors in accordance with the spec */
        if ( ! ase_dsc_cmp(forClone, forCopy) ) {
            if ( ase_dsc_isA(dsc) != kAseApiAppl ) {
                ads_printf("\nWrong comparision") ;
                printAseErr(forClone) ;
                break ;
            }
        }
        retCode = kAsiGood ;
    } while(0) ;
    ase_dsc_free(&forClone) ;
    ase_dsc_free(&forCopy) ;
    if ( retCode != kAsiGood ) {
        ads_printf("\nDescriptor test -> BAD") ;
    }
    return retCode ;
} /* end of testDsc() */

/****************************************************************************/
/*.doc printColDsc(internal) */
/*+
  Prints the column description
-*/
/****************************************************************************/
static void                               
/*FCN*/printColDsc(ASICOLDSC col) 
{
   ASIDATADSC    datadsc=0L;
   ASIIDENT      name=0L;
   char          buff [128];

     /* Print column name */
   asi_cdsc_name (col, &name);
   ads_printf("%s", asi_get_ident (name, buff, 128));
   asi_destroy_ident (&name);

     /* Print column type */
   if (asi_cdsc_ddsc (col, &datadsc) == kAsiGood) {
       ads_printf("  %s", asi_ddsc_sqltype (datadsc, buff, 256));
       asi_destroy_ddsc (&datadsc);
   }
} /* end of printColDsc() */


/****************************************************************************/
/*.doc printBufNames(internal) */
/*+
  This function prints just the string values from the specified buffer
-*/
/****************************************************************************/
static void        
/*FCN*/printBufNames(const struct resbuf *pBuf) 
{
    struct resbuf *ptr ;    /* scanning buffer pointer */
    for ( ptr = (struct resbuf*)pBuf ; ptr != NULL ; ptr = ptr->rbnext ) {
        if ( ptr->restype == RTSTR &&
             ptr->resval.rstring != NULL ) {
            ads_printf("\n%s", ptr->resval.rstring) ;
        }
    }
} /* end of printBufNames() */

/****************************************************************************/
/*.doc pauseInput(internal) */
/*+
  This function asks the user to press the key
-*/
/****************************************************************************/
static void
/*FCN*/pauseInput(const char* pPrompt)
{
    int ii ;
    if ( pPrompt != NULL ) {
        ads_getint(pPrompt, &ii) ;
    } else {
        ads_getint("\nPress any key...", &ii) ;
    }
} /* End of pauseInput() */

/****************************************************************************/
/*.doc callCmd(internal) */
/*+
  Calls AutoCAD command with the specified parameters.
-*/
/****************************************************************************/
static int
/*FCN*/callCmd(char *pCmdName, struct resbuf *pParms) 
{
    struct resbuf ocmdecho;           /* Current CMDECHO setting */
    struct resbuf tcmdecho;           /* Temporary CMDECHO setting */
    struct resbuf ocmddia;            /* Current CMDDIA setting */
    struct resbuf tcmddia;            /* Temporary CMDDIA setting */
    struct resbuf AseFunc ;           /* The ASE command item */
    int status;                       /* Command status */

    tcmdecho.restype = RTSHORT;       /* Temporary CMDECHO setting (OFF) */
    tcmdecho.resval.rint = 0;

    ads_getvar ("CMDECHO", &ocmdecho);  /* Read current setting */
    ads_setvar ("CMDECHO", &tcmdecho);  /* Temporary setting */

    tcmddia.restype = RTSHORT;       /* Temporary CMDDIA setting (OFF) */
    tcmddia.resval.rint = 0;

    ads_getvar ("CMDDIA", &ocmddia);  /* Read current setting */
    ads_setvar ("CMDDIA", &tcmddia);  /* Temporary setting */

      /* Chain the calling parameters */
    AseFunc.restype = RTSTR ;
    AseFunc.resval.rstring = pCmdName ;
    AseFunc.rbnext = pParms ;

    status = ads_cmd (&AseFunc);            /* Execute command */

    ads_setvar ("CMDECHO", &ocmdecho);  /* Reset CMDECHO */

    ads_setvar ("CMDDIA", &ocmdecho);  /* Reset CMDDIA */

    return status;
} /* end of callCmd() */

/****************************************************************************/
/*.doc  addtoken (internal) */
/*+
  This function adds new token to the static buffer.
  Serves to construct the SQL statements.
  Action depends on newtoken value:
    NEW_TOKENBUF    - free previous static buffer and allocate new one
    FREE_TOKENBUF   - free current pointer
    any other       - add string to the static buffer
  Return values:
    pointer to the static buffer. If error, returns NULL.
-*/
/****************************************************************************/
static char*
/*FCN*/addtoken (char *newtoken)             
{
    static char *curptr = NULL ;      /* default value */
    static int maxsize = 0 ;          /* maximun size of statement */
    int curpos = 0 ;                  /* current position in the buffer */
    int cursize;                      /* variable for checking */

      /* You need new list */
    if ( newtoken == NEW_TOKENBUF ) { 
          /* Check pointer */
        if ( curptr != NULL ) {   
              /* Free old memory block */
            free(curptr) ;        
            curptr = NULL ;
        }
        if ( (curptr = (char*)calloc(1, DEFSTMSIZE)) == NULL ) {
            ads_abort("\nNo memory") ;
            return NULL ;
        }
          /* Set default size of statement */
        maxsize = DEFSTMSIZE ;        
    } else if ( newtoken == FREE_TOKENBUF ) {
        if ( curptr != NULL ) {
            free(curptr) ;
            curptr = NULL ;
        }
    } else {
        if ( curptr != NULL ) {
            cursize = strlen (newtoken) ;
            if ( cursize ) {
                curpos = strlen(curptr) ;
                if ( curpos+cursize >= maxsize ) {
                    char *tmpptr;     /* temporary pointer */
                      /* new block size */
                    maxsize += cursize + DEFSTMINC ;       
                    if ( maxsize > MAXSTMSIZE ||
                         (tmpptr = (char*)calloc (1,  maxsize)) == NULL ) {
                        ads_abort("\nToo big statement size") ;
                          /* Free old buffer */
                        free(curptr) ;             
                        curptr = NULL ;
                        return NULL ;
                    }
                      /* Copy old data */
                    strcpy ( tmpptr, curptr) ;   
                      /* Free old block */
                    free (curptr) ;              
                      /* Set new pointer */
                    curptr = tmpptr ;                
                }
                strcpy (curptr+curpos, newtoken) ;
            }
        }
    }
      /* Return pointer to the buffer */
    return curptr ;                   
}  /* end of addtoken () */

/****************************************************************************/
/*.doc smpinit(internal) */
/*+
  This function initializes the ASI and ASE interfaces
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/smpinit() 
{
    char *ptr ;     /* ASE version string pointer */
      /* Init ASI interface */
    if ( asi_initasi(&AsiAppl) != kAsiGood ) {
        ads_abort("\nCan't initialize ASI interface") ;
        return kAsiBad ;
    }
      /* Init ASE interface */
    if ( (AseAppl = ase_appl_init()) == ASE_DSC_NULL ) {
        ads_abort("\nCan't initialize ASE interface") ;
        asi_termasi(&AsiAppl) ;
        return kAsiBad ;
    }
      /* Get ASE version */
    if ( (ptr=(char*)ase_dsc_version(AseAppl)) != NULL ) {
        ads_printf("\nASE version [%s] is detected", ptr) ;
    }
      /* Test ASE APPL */
    if ( testDsc(AseAppl) != kAsiGood ) {
        smpterm() ;
        return kAsiBad ;
    }
    return kAsiGood ;
} /* end of smpinit() */

/****************************************************************************/
/*.doc smpterm(internal) */
/*+
  This function terminates the ASI and ASE interfaces
-*/
/****************************************************************************/
static void
/*FCN*/smpterm() 
{
      /* Disconnect from the global Env */
    disconnect() ;
      /* Terminate ASE interface */
    ase_appl_term(&AseAppl) ;
      /* Terminate ASI interface */
    asi_termasi(&AsiAppl) ;
} /* end of smpterm() */

/****************************************************************************/
/*.doc isInit(internal) */
/*+
  This function checks whether or not ASE and ASI interfaces
  were initialized.
-*/
/****************************************************************************/
static EAsiBoolean 
/*FCN*/isInit() 
{
    if ( AsiAppl == 0L || AseAppl == ASE_DSC_NULL ) {
        ads_printf("\nASE or ASI interfaces wasn't initialized") ;
        return kAsiBad ;
    }
    return kAsiGood ;
} /* end of isInit() */

/****************************************************************************/
/*.doc loadfunc(internal) */
/*+
    This function is called to load external functions into AutoLISP.
-*/
/****************************************************************************/
static int
/*FCN*/loadfunc ()
{
    short i = sizeof(cmd) /
              sizeof(CMDADS);          /* Number of functions */

    while (i-- > 0)  {                     /* For every function from cmd */
        if (ads_defun(cmd[i].cmdname, i) != RTNORM) {
            return RSERR;                 /* Wrong function definition */
        }
    }

    if ( ! smpinit() ) {
        return RSERR ;
    }
    return RSRSLT;                    /* All functions were defined right */
}                                     /* End of loadfunc () */

/****************************************************************************/
/*.doc unloadfunc(internal) */
/*+
    This function is called to unload external functions into AutoLISP.
-*/
/****************************************************************************/
static int
/*FCN*/unloadfunc ()
{
    short i = sizeof(cmd) /
              sizeof(CMDADS);          /* Number of functions */

    while (i-- > 0) {                      /* For every function from cmd */
        if (ads_undef(cmd[i].cmdname, i) != RTNORM) {
            return RSERR;                 /* Wrong function definition */
        }
    }
    smpterm() ;
    return RTNORM ;                    /* All functions were defined right */
}                                     /* End of unloadfunc () */

/****************************************************************************/
/*.doc execfunc(internal) */
/*+
    This function is called to start external function.
-*/
/****************************************************************************/
static int
/*FCN*/execfunc ()
{
    int i = ads_getfuncode ();        /* Function number */

    if (i == RTERROR)
        return RSERR;                 /* Error */

    /* Call function */
    if ( (cmd[i].cmdfunc)() != kAsiGood ) {
        ads_printf("\nSample command %s failed", cmd[i].cmdname) ;
    }

    ads_retvoid() ;
    return RSRSLT;                    /* OK */
}                                     /* End of execfunc () */

/****************************************************************************/
/*.doc main(external) */
/*+
    Main entry point.
-*/
/****************************************************************************/
void
/*FCN*/main (
  int argc,                           /* Argument count */
  char *argv[]                        /* Argument vector */
){
    short scode = RSRSLT;             /* Default result code */
    int stat;                         /* Return value from ads_link */

    ads_init(argc, argv);             /* Initialize the interface */

    for (;;) {                        /* Main loop */
                                      /* Link with AutoCAD */
        if ((stat = ads_link (scode)) < 0) {  
                                      /* AutoCAD error */
                                      /* Print error message */
            printf("\nBad status from ads_link() = %d\n", stat);
            fflush (stdout);          /* Fflush the print buffer */
            exit (1);                 /* Exit */
        }

        scode = RSRSLT;                /* Default result value */

        switch (stat) {         

        case RQXLOAD:                 /* Load function by (xload) command */
	        scode = loadfunc ();       /* Register ADS external functions */
           break;

        case RQSUBR:                  /* Invoke function */
           scode = execfunc ();       /* Call function */
           break;

        case RQXUNLD:                 /* Unload application */
        case RQEND:                   /* End AutoCAD */
        case RQQUIT:                  /* Quit AutoCAD */
            unloadfunc() ;            /* Unload the commands */
            break ;
        }
    }
}                                     /* End of main () */

#endif /* ASE_ASESMP_C */
/*EOF*/


