/********************************************************************
* lindner
* 3.7
* 1994/07/03 23:10:57
* /home/arcwelder/GopherSrc/CVS/gopher+/gopher/form.c,v
* Exp
*
* Paul Lindner, University of Minnesota CIS.
*
* Copyright 1991, 92, 93, 94 by the Regents of the University of Minnesota
* see the file "Copyright" in the distribution for conditions of use.
*********************************************************************
* MODULE: form.c
* Form definition and management functions
*********************************************************************
* Revision History:
* form.c,v
* Revision 3.7 1994/07/03 23:10:57 lindner
* fix forms..
*
* Revision 3.6 1994/05/19 14:07:24 lindner
* use fast malloc on VMS VAXC
*
* Revision 3.5 1994/04/01 02:24:56 lindner
* Fix return types
*
* Revision 3.4 1994/03/08 15:55:05 lindner
* gcc -Wall fixes
*
* Revision 3.3 1994/03/04 23:39:50 lindner
* Fix for log entries
*
* Revision 3.2 1994/03/04 23:36:32 lindner
* bug fixes.
*
* Revision 3.1 1994/02/20 16:15:44 lindner
* New form definition and management functions
*
*
*********************************************************************/
#include "form.h"
#include "String.h"
#include "GSgopherobj.h"
#include "BLblock.h"
#include "Malloc.h"
#include "CURcurses.h"
#include "gopher.h"
/** Make a new item... **/
ITEM *
ITEMnew()
{
ITEM *temp;
temp = (ITEM*) malloc(sizeof(ITEM));
temp->type = ITEM_UNINIT;
temp->label = STRnew();
temp->response = STRnew();
temp->chooseitem = -1;
temp->choices = STAnew(3);
return(temp);
}
/*
* Clear out a specific item
*/
void
ITEMinit(item)
ITEM *item;
{
item->type = ITEM_UNINIT;
STRinit(item->label);
STRinit(item->response);
STAinit(item->choices);
item->chooseitem=0;
}
/*
* Copy an item
*/
ITEM*
ITEMcpy(dest, orig)
ITEM *dest, *orig;
{
dest->type = orig->type;
STRset(dest->label, STRget(orig->label));
STRset(dest->response, STRget(orig->response));
dest->chooseitem = orig->chooseitem;
STAcpy(dest->choices, orig->choices);
return(dest);
}
/*
* Nuke a defined ITEM
*/
void
ITEMdestroy(item)
ITEM *item;
{
STRdestroy(item->label);
STRdestroy(item->response);
STAdestroy(item->choices);
free(item);
}
/*
* Add an item to the list of choices..
*/
void
ITEMpushChoice(item, choice)
ITEM *item;
char *choice;
{
String *str;
str = STRnew();
STRset(str, choice);
STApush(item->choices, str);
STRdestroy(str);
}
/*************************************************************************
* Form definition routines.. Pretty swanky..
*/
FORM*
FORMfromASK(gs)
GopherObj *gs;
{
int Asknum;
Blockobj *bl;
char askline[256];
char *defaultval;
int i;
char ** responses = NULL;
ITEM *item;
FORM *form;
GSgetginfo(gs, TRUE);
bl = GSfindBlock(gs, "ASK");
if (bl == NULL)
return(NULL);
form = FORMnew(BLgetNumLines(bl));
for (Asknum=0; Asknum <BLgetNumLines(bl); Asknum++) {
char *askprompt, *cp;
strcpy(askline, BLgetLine(bl, Asknum));
/*** find the type of question ***/
askprompt = strchr(askline, ':');
if (askprompt == NULL) {
/* Empty line crashes CURRequest unless do this*/
FORMaddLabel(form, "");
continue;
}
*(askprompt+1) = '\0';
askprompt+=2;
/*** Zap the tabs, and load it up.. ***/
cp = strchr(askprompt, '\t');
if (cp != NULL) {
defaultval = cp+1;
*cp = '\0';
} else
defaultval = NULL;
if (strncasecmp(askline, "Note:", 5) == 0)
FORMaddLabel(form, askprompt);
else if (strncasecmp(askline, "Choose:", 7) == 0) {
int cnum = 0;
char **choices;
choices = (char**) malloc(sizeof(char*)*100);
/*** add list of choices to struct **/
while ((cp = strchr(defaultval, '\t')) != NULL) {
*cp = '\0';
choices[cnum++] = defaultval;
defaultval = cp+1;
}
if (defaultval != NULL)
choices[cnum++] = strdup(defaultval);
choices[cnum++] = NULL;
FORMaddChoice(form, askprompt, choices, 0);
}
else if (strncasecmp(askline, "Select:", 7) == 0) {
int chooseitem = 0;
cp = strrchr(askprompt, ':');
if (cp != NULL) {
*cp = '\0';
cp++;
if (*cp == '1')
chooseitem = 1;
}
FORMaddSelect(form, askprompt, chooseitem);
}
else if (strncasecmp(askline, "AskP:", 5)==0)
FORMaddPasswd(form, askprompt, defaultval);
else if (strncasecmp(askline, "AskL:", 5)==0)
FORMaddLong(form, askprompt, defaultval);
else if (strncasecmp(askline, "Choosef:", 8) == 0)
FORMaddFilechoice(form, askprompt, defaultval);
else
FORMaddPrompt(form, askprompt, defaultval);
}
}
char**
FORMgetAskdata(gs, form, Asknum)
GopherObj *gs;
FORM *form;
int Asknum;
{
char **responses;
int i;
ITEM *item;
if (!CURform(CursesScreen, GSgetTitle(gs), form)) {
int respnum = 0;
responses = (char**) malloc(sizeof(char*)*(1+Asknum));
for (i=0; i <Asknum; i++) {
item = FORMgetEntry(form, i);
switch (ITEMgetType(item)) {
case ITEM_LONG:
responses[respnum++] = strdup("1");
responses[respnum++] = strdup(ITEMgetResponse(item));
break;
case ITEM_SELECT:
if (ITEMgetChoice(item) == 0)
responses[respnum++] = strdup("0");
else
responses[respnum++] = strdup("1");
break;
case ITEM_CHOICE:
responses[respnum++] = strdup(ITEMgetChoiceNum(item, ITEMgetChoice(item)));
break;
case ITEM_PROMPT:
case ITEM_PASSWD:
responses[respnum++] = strdup(ITEMgetResponse(item));
}
}
responses[respnum++] = NULL;
}
/*** Free memory ***/
FORMdestroy(form);
return(responses);
}
boolean
FORMaddLabel(form, label)
FORM *form;
char *label;
{
ITEM *item;
item = ITEMnew();
ITEMsetType(item, ITEM_LABEL);
ITEMsetLabel(item, label);
FORMpush(form, item);
ITEMdestroy(item);
return(TRUE);
}
boolean
FORMaddPrompt(form, prompt, defval)
FORM *form;
char *prompt;
char *defval;
{
ITEM *item;
item = ITEMnew();
ITEMsetType(item, ITEM_PROMPT);
if (prompt != NULL)
ITEMsetLabel(item, prompt);
else
ITEMsetLabel(item, "");
if (defval != NULL)
ITEMsetResponse(item, defval);
else
ITEMsetResponse(item, "");
FORMpush(form, item);
ITEMdestroy(item);
return(TRUE);
}
boolean
FORMaddPasswd(form, prompt, defval)
FORM *form;
char *prompt;
char *defval;
{
FORMaddPrompt(form, prompt, defval);
ITEMsetType(FORMgetEntry(form, FORMgetTop(form)-1), ITEM_PASSWD);
return(TRUE);
}
boolean
FORMaddFilechoice(form, prompt, defval)
FORM *form;
char *prompt;
char *defval;
{
FORMaddPrompt(form, prompt, defval);
ITEMsetType(FORMgetEntry(form, FORMgetTop(form)-1), ITEM_FILENAME);
return(TRUE);
}
boolean
FORMaddLong(form, prompt, defval)
FORM *form;
char *prompt;
char *defval;
{
FORMaddPrompt(form, prompt, defval);
ITEMsetType(FORMgetEntry(form, FORMgetTop(form)-1), ITEM_LONG);
return(TRUE);
}
/*
* add a multiple choice item..
*/
boolean
FORMaddChoice(form, prompt, choices, defval)
FORM *form;
char *prompt;
char **choices;
int defval;
{
ITEM *item;
int i=0;
FORMaddPrompt(form, prompt, "");
item = FORMgetEntry(form, FORMgetTop(form)-1);
ITEMsetChoice(item, defval);
ITEMsetType(item, ITEM_CHOICE);
while (choices[i] != NULL) {
ITEMpushChoice(item, choices[i]);
i++;
}
return(TRUE);
}
boolean
FORMaddSelect(form, prompt, defval)
FORM *form;
char *prompt;
int defval;
{
ITEM *item;
FORMaddPrompt(form, prompt, "");
item = FORMgetEntry(form, FORMgetTop(form)-1);
ITEMsetChoice(item, defval);
ITEMpushChoice(item, "No");
ITEMpushChoice(item, "Yes");
ITEMsetType(item, ITEM_SELECT);
return(TRUE);
}
/*
* Display a form and allow a user to fill it out.
*/
int
CURform(cur,Wintitle,form)
CursesObj *cur;
char *Wintitle;
FORM *form;
{
WINDOW *tempwin;
int i,j;
int totalprompts;
int numprompts=0;
int maxpromptwidth =0;
int currentfield = 0;
int maxlength = COLS-7;
char TrimmedTitle[128];
ITEM *item;
int ch;
int numforms = 1;
int currentform = 0;
int pagesize = LINES-8;
int thisformdone = FALSE;
/** Find the number of prompts... and the max width***/
for (totalprompts = 0; totalprompts < FORMgetTop(form); totalprompts++) {
item = FORMgetEntry(form, totalprompts);
/*** Skip non editable prompts ***/
if (item != NULL && ITEMgetType(item) != ITEM_LABEL) {
if (strlen(ITEMgetPrompt(item)) > maxpromptwidth)
maxpromptwidth = strlen(ITEMgetPrompt(item));
}
if (totalprompts != 0 && (totalprompts % pagesize) == 0)
numforms ++;
}
if (numforms > 1)
numprompts = pagesize;
else
numprompts = totalprompts;
if (numprompts == 0) {
return(-1);
}
maxlength -= (maxpromptwidth+1);
tempwin = newwin(6 + numprompts, COLS-2, (LINES-(6+numprompts))/2,1);
CURwenter(cur,tempwin);
while (currentform < numforms) {
if (currentform == (numforms-1)) {
numprompts = totalprompts - (pagesize * currentform);
} else {
numprompts = pagesize ;
}
wstandend(tempwin);
CURbox(cur,tempwin, 6+numprompts, COLS-2);
currentfield = 0;
/*** Add the window title, centered ***/
if (Wintitle != NULL) {
/** Trim window title to fit in the window **/
if (strlen(Wintitle) > COLS-2) {
strncpy(TrimmedTitle, Wintitle, COLS-2);
TrimmedTitle[COLS-5] = '.';
TrimmedTitle[COLS-4] = '.';
TrimmedTitle[COLS-3] = '.';
TrimmedTitle[COLS-2] = '\0';
}
else
strcpy(TrimmedTitle, Wintitle);
/** Put the title, bold **/
wmove(tempwin, 0,(COLS -2 - strlen(TrimmedTitle))/2);
wstandout(tempwin);
waddstr(tempwin, TrimmedTitle);
wstandend(tempwin);
}
/** Add the prompts and typing area **/
for (i=0; i <numprompts; i++) {
item = FORMgetEntry(form, i + currentform*pagesize);
wmove(tempwin, 2+i, 2);
waddstr(tempwin, ITEMgetPrompt(item));
switch (ITEMgetType(item)) {
case ITEM_LABEL:
break;
case ITEM_SELECT:
case ITEM_CHOICE:
/** Add the default **/
wmove(tempwin, 2+i, maxpromptwidth +4);
waddstr(tempwin, ITEMgetChoiceNum(item, ITEMgetChoice(item)));
break;
default:
/** Add the black space for the stowage, **/
/** and the stowage, if it exists **/
wmove(tempwin, 2+i, maxpromptwidth +4);
wstandout(tempwin);
if (ITEMgetType(item) == ITEM_PASSWD) {
int numchars = strlen(ITEMgetResponse(item));
for (j=0; j<numchars; j++)
waddch(tempwin, '*');
} else
waddstr(tempwin, ITEMgetResponse(item));
for (j=strlen(ITEMgetResponse(item))+maxpromptwidth+4;
j< COLS-6; j++) {
waddch(tempwin, ' ');
}
wstandend(tempwin);
}
}
/** Add the labels, centered **/
wmove(tempwin, 3 + numprompts, (COLS-63)/2);
CURbutton(cur, tempwin, "Switch Fields: TAB", FALSE);
CURbutton(cur, tempwin, "Cancel: ^G", FALSE);
waddch(tempwin, ' ');
CURbutton(cur, tempwin, "Erase: ^U", FALSE);
waddch(tempwin, ' ');
CURbutton(cur, tempwin, "Accept: Enter", FALSE);
touchwin(tempwin);
wrefresh(tempwin);
thisformdone = FALSE;
while (!thisformdone) {
boolean hidden;
int oldchoice;
item = FORMgetEntry(form, currentfield + currentform*pagesize);
if (ITEMgetType(item) == ITEM_PASSWD)
hidden = TRUE;
else
hidden = FALSE;
wmove(tempwin, 2+currentfield, maxpromptwidth +4);
wrefresh(tempwin);
if (ITEMgetType(item) == ITEM_CHOICE ||
ITEMgetType(item) == ITEM_SELECT) {
int choice = ITEMgetChoice(item);
int done = FALSE;
wmove(tempwin, 4+numprompts, (COLS-22)/2);
CURbutton(cur, tempwin, "Cycle Values: SPACE", FALSE);
wmove(tempwin, 2+currentfield, maxpromptwidth +
strlen(ITEMgetChoiceNum(item, choice)) +4);
wrefresh(tempwin);
while (!done) {
ch = CURgetch(cur);
oldchoice = choice;
if (ch == ' ')
choice ++;
else
done = TRUE;
if (choice == ITEMgetNumChoices(item))
choice = 0;
/*** Erase old choice.. ***/
wmove(tempwin, 2+currentfield, maxpromptwidth + 4);
for (i=strlen(ITEMgetChoiceNum(item, oldchoice)); i>0; i--)
waddch(tempwin, ' ');
wmove(tempwin, 2+currentfield, maxpromptwidth + 4);
waddstr(tempwin, ITEMgetChoiceNum(item,choice));
ITEMsetChoice(item, choice);
wrefresh(tempwin);
}
wmove(tempwin, 4+numprompts, (COLS-22)/2);
waddstr(tempwin, " ");
} else if (ITEMgetType(item) == ITEM_LABEL)
ch = '\t';
else {
char tmpbuffer[256];
tmpbuffer[0] = '\0';
if (ITEMgetResponse(item) != NULL)
strcpy(tmpbuffer, ITEMgetResponse(item));
ch = CURwgetstr(cur,tempwin,ITEMgetResponse(item),
maxlength, hidden);
ITEMsetResponse(item, tmpbuffer);
}
switch (ch) {
case '\t':
case KEY_DOWN:
/*** Move to another field ***/
do {
currentfield = (currentfield +1) % numprompts;
} while (currentfield == numprompts ||
ITEMgetType(FORMgetEntry(form, currentfield +
currentform * pagesize))
== ITEM_LABEL);
break;
case KEY_UP:
do {
currentfield--;
if (currentfield <0)
currentfield = numprompts-1;
} while (ITEMgetType(FORMgetEntry(form, currentfield +
currentform * pagesize))
== ITEM_LABEL);
break;
case '\007':
case -1:
/*** Cancel ***/
delwin(tempwin);
return(-1);
case '\n':
currentform++;
if (currentform == numforms) {
delwin(tempwin);
return(0);
} else {
wclear(tempwin);
thisformdone = TRUE;
}
break;
}
}
}
}