home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1990 by Borland International, Inc. */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <string.h>
- #include <ctype.h>
- #include "pxengine.h"
-
- /*
- * FONEDEX.C
- * Simple electronic file card application
- *
- * Description:
- * Allows simple database design and access of an electronic file card
- * database. Records can be added, deleted, updated and searched
- * in a multiuser environment.
- *
- * The structure of new tables is kept in the ASCII file
- * STRUCTUREFILE. Each line of the file represents a field
- * in the Paradox table DATAFILE. It has the format:
- * <field type> <field name>
- * where <field name> and <field type> are legal Paradox names and
- * field types.
- *
- * Compilation:
- * To compile and link the example program, make sure that your C compiler
- * has been correctly installed. Compile the program using the large
- * memory model specification:
- * Turbo C: Option -ml
- * Microsoft C: Option /AL
- *
- * Execution:
- * To run the example program enter the following command:
- * fonedex
- * You can then choose different options through a very simple menu
- * interface.
- */
-
- #define NULLCHAR '\0'
-
- #define SUCCESS 0
- #define FAIL -1
-
- #define MAXFIELDS 20
- #define MAXFIELDSIZE 50
-
- #define STRUCTUREFILE "fonedex.dat"
- #define DATAFILE "fonedex"
-
- /* Defines for PXNetInit
- (modify these defines to match your network) */
- #define USERNAME "Engine"
- #define NETTYPE NOTONNET
- #define NETDIR ""
-
- typedef struct
- {
- int key; /* keystroke to activate this option */
- char *name; /* menu option name */
- void (*func)(void); /* menu function to be called */
- } MENU;
-
- /* Globals */
- RECORDHANDLE recHandle; /* record buffer */
- TABLEHANDLE tblHandle; /* table handle */
- char *names[MAXFIELDS]; /* field names */
- char *types[MAXFIELDS]; /* field types */
- int TableIsOpen = FALSE; /* table is open */
- int nfields; /* number of fields */
-
- /* Function prototypes */
- int main(void);
- int LoadTableStructure(void);
- int GetTableStructure(void);
- void FreeTableStructure(void);
- int InputRecord(void);
- int InputField(int *);
- void menu(MENU *, int, char *);
- void ProcessSearch(int);
- void SearchUpdate(void);
- void OpenFonedex(void);
- void NewFonedex(void);
- void CloseFonedex(void);
- void AddEntry(void);
- void Search(void);
- int GetData(FIELDHANDLE, char *);
- int PutData(FIELDHANDLE, char *);
- void strip(char *);
- int Error(int);
-
- MENU MainMenu[] =
- {
- { '1', "New Fonedex", NewFonedex },
- { '2', "Open Fonedex", OpenFonedex },
- { '3', "Close Fonedex", CloseFonedex },
- { '4', "Add Entry", AddEntry },
- { '5', "Search", Search },
- { '6', "Quit", NULL }
- };
-
- #define SIZEMAINMENU (sizeof(MainMenu) / sizeof(MENU))
-
- /*
- * Function:
- * main
- *
- * Arguments:
- * None
- *
- * Description:
- * Initializes the engine and calls the main menu
- * When the main menu returns, the table is closed
- * if it was left open.
- *
- * Returns:
- * None
- *
- */
- int main(void)
- {
-
- /* Initialize the Engine */
- if (Error(PXNetInit(NETDIR, NETTYPE, USERNAME)))
- exit(1);
-
- /* Load the main menu */
- menu(MainMenu, SIZEMAINMENU, "Main Menu");
-
- /* Close table if open */
- if (TableIsOpen)
- CloseFonedex();
-
- /* Terminate the Engine */
- return(Error(PXExit()));
- }
-
- /*
- * Function:
- * menu
- *
- * Arguments:
- * menu Pointer to array of menu entries
- * size Number of menu entries
- * title Name of menu
- *
- * Description:
- * Displays a menu structure, gets a valid menu response
- * and dispatches to the appropriate function.
- *
- * Returns:
- * None
- *
- */
- void menu(MENU *menu, int size, char *title)
- {
- int i;
- int c;
-
- while (TRUE)
- {
- /* Display the title */
- printf("\n%s\n", title);
-
- /* Display the menu options */
- for (i = 0; i < size; i++)
- printf("%c\t%s\n", menu[i].key, menu[i].name);
-
- /* Get a key from the user */
- c = getch();
-
- /* See if we can find a match in the menu structure */
- for (i = 0; i < size; i++)
- if (c == menu[i].key)
- break;
-
- /* If option found... */
- if (i < size)
- {
- /* Dispatch the function unless function name is NULL,
- which means to terminate this menu */
- if (menu[i].func)
- (*menu[i].func)();
- else
- return;
- }
- else
- printf("Invalid option.\n");
- }
- }
-
- /*
- * Function:
- * NewFonedex
- *
- * Arguments:
- * None
- *
- * Description:
- * Create a new FONEDEX database. The structure of this data
- * base is read in from an ASCII disk file.
- *
- * Returns:
- * None
- */
- void NewFonedex(void)
- {
- /* First load the structure of the table from an ASCII data file */
- if (LoadTableStructure() == FAIL)
- {
- printf("FONEDEX: Cannot load table structure\n");
- return;
- }
-
- /* Now try and create it */
- if (Error(PXTblCreate(DATAFILE, nfields, names, types)))
- return;
-
- /* Free up the table structure */
- FreeTableStructure();
- }
-
- /*
- * Function:
- * LoadTableStructure
- *
- * Arguments:
- * None
- *
- * Description:
- * Loads a table structure from an ASCII disk file.
- *
- * Returns:
- * SUCCESS structure loaded
- * FAIL error occurred
- */
- int LoadTableStructure(void)
- {
- FILE *fp;
- char name[BUFSIZ];
- char type[BUFSIZ];
-
- /* Open the structure file */
- if ((fp = fopen(STRUCTUREFILE, "r")) == NULL)
- {
- perror(STRUCTUREFILE);
- return(FAIL);
- }
-
- /* Read in the structure */
- nfields = 0;
-
- while (! feof(fp) && nfields < MAXFIELDS)
- {
- /* read data, beware of unexpected EOF */
- if (fscanf(fp, "%s",type) != 1)
- break;
-
- if (fgets(name,BUFSIZ,fp) == NULL)
- break;
-
- /* remove trailing and leading white space from name */
- strip(name);
-
- names[nfields] = strdup(name);
- types[nfields++] = strdup(type);
-
- }
-
- /* Return error if no fields were found */
- if (! nfields)
- return(FAIL);
-
- fclose(fp);
- return(SUCCESS);
- }
-
- /*
- * Function:
- * GetTableStructure
- *
- * Arguments:
- * None
- *
- * Description:
- * Retrieves table field names and types.
- *
- * Returns:
- * SUCCESS structure loaded
- * FAIL error occurred
- */
- int GetTableStructure(void)
- {
- char name[BUFSIZ];
- char type[BUFSIZ];
- FIELDHANDLE i;
-
- nfields = 0;
- Error(PXRecNFlds(tblHandle,&nfields));
- for (i=1;i<=nfields;++i)
- if (!Error(PXFldName(tblHandle,i,BUFSIZ,name)) &&
- !Error(PXFldType(tblHandle,i,BUFSIZ,type)) )
- {
- names[i - 1] = strdup(name);
- types[i - 1] = strdup(type);
- }
- else
- return(FAIL);
-
- return(SUCCESS);
- }
-
- /*
- * Function:
- * FreeTableStructure
- *
- * Arguments:
- * None
- *
- * Description:
- * Frees memory associated with table structure
- *
- * Returns:
- * None
- */
- void FreeTableStructure(void)
- {
- int i;
-
- for (i = 0; i < nfields; i++)
- {
- free(names[i]);
- free(types[i]);
- }
- }
-
- /*
- * Function:
- * OpenFonedex
- *
- * Arguments:
- * None
- *
- * Description:
- * Opens the fonedex table
- *
- * Returns:
- * None
- */
- void OpenFonedex(void)
- {
- /* Attempt to open the table and allocate a record buffer. If table
- is open, inidicate an error */
- if (TableIsOpen)
- {
- printf("Table already opened\n");
- return;
- }
-
- /* Now try and open the table */
- if (Error(PXTblOpen(DATAFILE, &tblHandle, 0, 0)))
- return;
-
- /* Allocate a record buffer */
- if (Error(PXRecBufOpen(tblHandle, &recHandle)))
- return;
-
- if (GetTableStructure() == FAIL)
- return;
- TableIsOpen = TRUE;
- }
-
- /*
- * Function:
- * CloseFonedex
- *
- * Arguments:
- * None
- *
- * Description:
- * Closes the fonedex table if opened
- *
- * Returns:
- * None
- */
- void CloseFonedex(void)
- {
-
- if (! TableIsOpen)
- {
- printf("Table not open\n");
- return;
- }
-
- /* Free the record buffer */
- if (Error(PXRecBufClose(recHandle)))
- return;
-
- /* Close the table */
- if (Error(PXTblClose(tblHandle)))
- return;
-
- FreeTableStructure();
- TableIsOpen = FALSE;
- }
-
- /*
- * Function:
- * AddEntry
- *
- * Arguments:
- * None
- *
- * Description:
- * Add a new record to the fonedex table
- *
- * Returns:
- * None
- */
- void AddEntry(void)
- {
-
- if (! TableIsOpen)
- {
- printf("Table not opened\n");
- return;
- }
-
- /* Empty the current record buffer */
- if (Error(PXRecBufEmpty(recHandle)))
- return;
-
- /* get the fields unless input is cancelled by user */
- if (InputRecord() == FAIL)
- return;
-
- /* Attempt to append the record */
- Error(PXRecAppend(tblHandle, recHandle));
- }
-
- /*
- * Function:
- * InputRecord
- *
- * Arguments:
- * None
- *
- * Description:
- * Allows editing of an existing record buffer and lets
- * user accept, cancel, or re-edit.
- *
- * Returns:
- * SUCCESS User accepts changes
- * FAIL Changes declined
- */
- int InputRecord(void)
- {
- int c;
- int i;
- char buf[BUFSIZ];
-
- /* Keep attempting to input until user selectes DONE or CANCEL */
- while (TRUE)
- {
- /* Go through all fields */
- for (i = 0; i < nfields; i++)
- {
- /* Translate the current value into the input buffer */
- if (( GetData(i + 1, buf)) != SUCCESS)
- return(FAIL);
-
- printf("%s\n", buf);
- /* Ask for the new value */
- printf("%s: ", names[i]);
- gets(buf);
-
- /* Now translate it back into the record buffer unless old value
- is kept by just pressing Return. */
- if (buf[0])
- if ((PutData(i + 1, buf)) != SUCCESS)
- return(FAIL);
- }
- /* Ask what to do with this input */
- printf("[S] Save, [C] Cancel, [R] Redo:\n");
- while (TRUE)
- {
- c = getch();
- if (c == 'S' || c == 's')
- return(SUCCESS);
- else
- if (c == 'C' || c == 'c')
- return(FAIL);
- else
- if (c == 'R' || c == 'r')
- break;
- }
- }
- }
-
- /*
- * Function:
- * Search
- *
- * Arguments:
- * None
- *
- * Description:
- * Search functions
- *
- * Returns:
- * None
- */
- void Search(void)
- {
- int FieldNumber;
- int i;
-
- /* Make sure table is opened */
- if (! TableIsOpen)
- {
- printf("Table not open\n");
- return;
- }
-
- /* Refresh the database in case anyone else has updated it */
- PXNetTblRefresh(tblHandle);
-
- /* List the fields to search on */
- printf("Select Field\n");
- for (i = 0; i < nfields; i++)
- printf("%d %s\n", i + 1, names[i]);
-
- /* Get the input field to search on */
- if (InputField(&FieldNumber) == FAIL)
- return;
-
- /* Perform search options */
- ProcessSearch(FieldNumber);
- }
-
- /*
- * Function:
- * InputField
- *
- * Arguments:
- * FieldNumber Field number selected
- *
- * Description:
- * Displays and accepts a legal field number
- *
- * Returns:
- * SUCCESS valid field number entered
- * FAIL invalid field number entered
- */
- int InputField(int *FieldNumber)
- {
- char buf[BUFSIZ];
-
- /* Get the field number as an integer*/
- *FieldNumber = getch() - '0';
-
- if (*FieldNumber < 1 || *FieldNumber > nfields)
- {
- printf("Illegal field number\n");
- return(FAIL);
- }
- /* Input the field */
- printf("%s: ", names[*FieldNumber - 1]);
- gets(buf);
-
- /* And translate it */
- if (PutData( *FieldNumber, buf) != SUCCESS)
- return(FAIL);
-
- return(SUCCESS);
- }
-
- /*
- * Function:
- * ProcessSearch
- *
- * Arguments:
- * FieldNumber field number to search on
- *
- * Description:
- * Performs actual search on given field. Allows user to
- * delete and u date records.
- *
- * Returns:
- * None
- */
- void ProcessSearch(int FieldNumber)
- {
- int mode = SEARCHFIRST;
- int i;
- int done = 1;
- char buf[BUFSIZ];
-
- while (TRUE)
- {
- /* If no match found, get out */
- if ((PXSrchFld(tblHandle, recHandle, FieldNumber, mode))
- != PXSUCCESS)
- {
- printf("No Matches\n");
- return;
- }
-
- /* Get the record found */
-
- if (Error(PXRecGet(tblHandle, recHandle)))
- return;
-
- /* Print the record */
- for (i = 0; i < nfields; i++)
- {
- if (GetData(i + 1, buf) != SUCCESS)
- return;
- printf("%s: %s\n", names[i], buf);
- }
-
- printf("[N] Next, [D] Delete, [U] Update, [E] Exit Search:\n");
- do
- {
- switch(getch())
- {
- case 'n':
- case 'N':
- /* Search for the next occurrence */
- mode = SEARCHNEXT;
- done = 1;
- break;
- case 'd':
- case 'D':
- Error(PXRecDelete(tblHandle));
- return;
- case 'u':
- case 'U':
- SearchUpdate();
- return;
- case 'e':
- case 'E':
- return;
- default:
- done = 0;
- }
- } while (!done);
- }
- }
-
- /*
- * Function:
- * SearchUpdate
- *
- * Arguments:
- * None
- *
- * Description:
- * Edits and Updates the currently selected record. Record
- * locking is used to stop multiple updates.
- *
- * Returns:
- *
- */
- void SearchUpdate(void)
- {
- LOCKHANDLE lckHandle;
-
- /* Lock the record */
- if (Error(PXNetRecLock(tblHandle, &lckHandle)))
- return;
-
- /* Edit the record */
- if (InputRecord() != FAIL)
- /* Update it */
- if (Error(PXRecUpdate(tblHandle, recHandle)))
- return;
-
- /* And unlock it */
- if (Error(PXNetRecUnlock(tblHandle, lckHandle)))
- return;
- }
-
- /*
- * Function:
- * GetData
- *
- * Arguments:
- * FieldNumber field number to retrieve data
- * s string where data is stored
- *
- * Description:
- * Retrieves in a string format any valid Paradox type.
- *
- * Returns:
- * SUCCESS No errors retrieving data
- * FAIL Error retrieving data
- */
-
- int GetData(FIELDHANDLE fh, char s[])
- {
- long theDate;
- int month, day, year;
- double theValue;
- short theShort;
- int isBlank;
-
- /* If this field is blank, we want to return a blank string */
- if (!Error(PXFldBlank(recHandle,fh,&isBlank)))
- {
- if (isBlank)
- {
- s[0] = NULLCHAR;
- return SUCCESS;
- }
- }
- else
- return FAIL;
-
- switch(types[fh-1][0])
- {
- case 'a':
- case 'A':
- if (Error(PXGetAlpha(recHandle,fh,BUFSIZ,s)))
- return FAIL;
- break;
- case 'd':
- case 'D':
- if (!Error(PXGetDate(recHandle,fh,&theDate)))
- {
- PXDateDecode(theDate,&month,&day,&year);
- sprintf(s,"%d/%d/%d",month,day,year);
- }
- else
- return FAIL;
- break;
- case 'n':
- case 'N':
- if (!Error(PXGetDoub(recHandle,fh,&theValue)))
- sprintf(s,"%5.0lf",theValue);
- else
- return FAIL;
- break;
- case '$':
- if (!Error(PXGetDoub(recHandle,fh,&theValue)))
- sprintf(s,"%4.2lf",theValue);
- else
- return FAIL;
- break;
- case 's':
- case 'S':
- if (!Error(PXGetShort(recHandle,fh,&theShort)))
- sprintf(s,"%d",theShort);
- else
- return FAIL;
- break;
- }
- return(SUCCESS);
- }
-
- /*
- * Function:
- * PutData
- *
- * Arguments:
- * FieldNumber field number to store data
- * s string to be stored
- *
- * Description:
- * Stores a string in any valid Paradox type.
- *
- * Returns:
- * SUCCESS No errors storing data
- * FAIL Error storing data
- */
-
- int PutData(FIELDHANDLE fh, char * s)
- {
- long theDate;
- int month, day, year;
- double theValue;
- short theShort;
-
- switch(types[fh-1][0])
- {
- case 'a':
- case 'A':
- if (Error(PXPutAlpha(recHandle,fh,s)))
- return FAIL;
- break;
-
- case 'D':
- case 'd':
- sscanf(s,"%d/%d/%d",&month,&day,&year);
- if (Error(PXDateEncode(month,day,year,&theDate)) ||
- Error(PXPutDate(recHandle,fh,theDate)))
- return FAIL;
- break;
-
- case '$':
- case 'N':
- case 'n':
- sscanf(s,"%lf",&theValue);
- if (Error(PXPutDoub(recHandle,fh,theValue)))
- return FAIL;
- break;
- case 'S':
- case 's':
- sscanf(s,"%d",&theShort);
- if (Error(PXPutShort(recHandle,fh,theShort)))
- return FAIL;
- break;
- }
-
- return(SUCCESS);
- }
-
- /*
- * Function:
- * Strip
- *
- * Arguments:
- * s String to be stripped of white space.
- *
- * Description:
- * Strips a string of leading and trailing white space.
- *
- * Returns:
- * void
- */
-
- void strip(char * source)
- {
- char * s = source, * d = source;
-
- while (*s != '\0' && isspace(*s))
- s++;
-
- while (*s != '\0' && *s != '\n')
- *(d++) = *(s++);
-
- *d = '\0';
- --d;
- while (*d == ' ')
- *(d--) = '\0';
- }
-
- /*
- * Function:
- * Error
- *
- * Arguments:
- * rc return code from a PX... function
- *
- * Description:
- * Prints error message if an error has occurred.
- *
- * Returns:
- * Current error code
- */
- int Error(int rc)
- {
-
- if (rc != PXSUCCESS)
- printf("FONEDEX: %s\n",PXErrMsg(rc));
-
- return rc;
- }