/* @(#)tfield.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:03 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++ .NAME tfield.c .TYPE Module .LANGUAGE C .KEYWORDS Forms .ENVIRONMENT TermWindows .AUTHOR Alan Richmond, Francois Ochsenbein .VERSION 1.0 07-Jun-1989: Extracted from Proteus. .COMMENTS This module contains the basic operations on Fields: creation, destruction, retrieval, remove. \begin{TeX} The field types can be: \begin{itemize} \item {\tt i$n$} Integer ($n=$1, 2 or 4) \item {\tt d$n$} Floating-point number \item {\tt c$n$} Character, case sensitive \item {\tt C$n$} Character, case insensitive \item {\tt $*$} Action field \end{itemize} {\bf Modifiers} can be \begin{itemize} \item {\tt t} Time (origin 1-Jan-1980) \item {\tt T} Time (origin 1-Jan-1970) \item {\tt D} Display-only field \item {\tt E} No-echo field (typically for Passwords) \item {\tt M} Field CAN BE modifed by other fields. \item {\tt R} Raw Field (Display Control Characters) \end{itemize} The field types may be: integer float string action \end{TeX} -----------------*/ #define PM_LEVEL LEVEL_TF #define PASCAL_DEF 0 /* Don't include Pascalisation */ #include /* Standard definitions */ #include /* for form values */ #include /* String utilities */ #include /* Conversion utilities */ #define FINISH goto FIN /*=====================================================================*/ int tff_anew(form, name, type, edit, text, attr, action) /*++++++++ .PURPOSE Install a new Field as name_of_Field (blank) Field. Items are aligned. .RETURNS OK / NOK (Doesn't fit) .REMARKS The size of the field is defined by text or edit, depending on type. -------------*/ TFORM *form; /* IN: The Form concerned */ char *name; /* IN: field name */ char *type; /* IN: field type */ char *edit; /* IN: field picture OR action */ char *text; /* IN: Text in the Field */ int attr; /* IN: Field Attribute (video) */ TF_FCT action; /* IN: Function (TFORM) action */ { int ln, len, nb, total_len, i, j, status; WINDOW *w; static char blanks[9] = " "; short where[2]; ENTER("tff_anew"); status = NOK; w = form->window; i = w->pos/w->dim[1]; j = w->pos%w->dim[1]; /* Current Position */ /* Determine the length of the Field */ if (*type == '*') /* Action Field */ len = strlen(text); else if (toupper(*type) == 'C') /* Char Field */ len = atoi(type+1); else len = strlen(edit); /* See if it fits on the Line */ if (*type != '*') /* Write Field Name */ { ln = strlen(name); nb = 7 - ((j+ln)&7); /* Padding Blanks */ total_len = ln+nb+len+1; if ((j+total_len) > w->dim[1]) /* Name doesn't fit */ i++, j = 0, w->pos = w->dim[1]*i, nb = 7 - (ln&7); total_len = ln+nb+len+1; } else total_len = len; if ((w->pos + total_len) > w->marker[1]) FINISH; if (*type != '*') /* Write Field Name */ Write(w, blanks, nb), Write(w, name, ln), Write(w, blanks, 1); j = SetAttr(w, attr); /* Save Old Attribute */ GetCursor(w, where); nb = len; /* Blanks to fill field */ if (text) /* Write Out the Text */ { ln = strlen(text); ln = MIN(ln, len); Write(w, text, ln); nb -= ln; /* Remaining blanks */ } for(; nb > 0; nb -= 8) /* Write Blanks */ Write(w, blanks, MIN(nb, 8)); SetAttr(w, j); /* Reset Old Attribute */ w->pos += 1; /* For Next field */ /* Install New Field */ status = tff_new(form, name, type, edit, where[0], where[1], 1, len, action) ; if (status > 0) status = OK; FIN: EXIT(status); } /*=====================================================================*/ int tff_new(form, name, type, edit, line, col, lines, cols, action) /*++++++++ .PURPOSE Load a form field with no default, and format picture. .RETURNS Maximum length of field (0 if field cannot fit on Window) .REMARKS The field size is (lines * cols). When lines>1, a multiline field is created; note that the number of columns cols may be larger than the window width. Values of zero for lines and cols lead to defaults computed from other parameters. The attribute and the contents of the field are taken directly from the Window. Scaling factors may be specified in the type, to be applied on values before display. In this implementation we only treat integer divisors. Strings supplied for name, type, picture are NOT saved (only addresses are kept). The current field in the form is the new one. -------------*/ TFORM *form; /* IN: The Form concerned */ char *name; /* IN: field name */ char *type; /* IN: field type */ char *edit; /* IN: field picture */ int line; /* IN: screen home row (from 0) */ int col; /* IN: screen home col (from 0)*/ int lines; /* IN: Number of Lines or 0 */ int cols; /* IN: Number of Columns or 0 */ TF_FCT action; /* IN: Function (TFORM) action */ { int fn, i; /* field number */ TFIELD *field; int flen; /* max. length */ char *p; WINDOW *w; int old_pos; ENTER("+tff_new"); if ( (lines == 0) && cols) lines = 1; flen = lines * cols; fn = (form->nfields)++; if (fn >= form->mfields) { ERR_ED_STRING(" Form capacity exceeded for ", form->name); flen = 0; FINISH; } form->ifield = fn; field = form->fields + fn; w = form->window; old_pos = w->pos; CursorTo (w, line, col); p = (type ? type : ""); /* --- Insert the New Field --- */ field->name = name; /* field name */ field->pos[0] = line; /* row */ field->pos[1] = col; /* col */ /* Get and Reset Video */ field->attr = SetAttr(w, SetAttr(w,_ATTRIBUTE_)); field->type = _DTYPE_STR; /* default type */ if (flen) field->string_size = ++flen, /* value string maxlen */ field->string = MEM_GET(char, flen), /* value string */ *(field->string) = EOS; else field->string_size = 0, /* value string maxlen */ field->string = NULL_PTR(char); i = strlen(p); i = MIN(i, 255); field->value.action = action; /* Action */ field->picture = edit; /* picture */ field->factor = 1; /* Default Factor */ field->options = _FIELD_TOSCREEN | _FIELD_TOFILE |_FIELD_MODIFIED; field->parm_size = i; /* strlen(p) */ field->parm = p; /* e.g. i4 */ field->note = NULL_PTR(char); /* Optional Note*/ /* Derive the type of Data as _DTYPE_INT, double, string */ tff_dset(field, field->parm); /* Routine in TFPIC */ /* non-string fields can't lay over several lines */ if_not(ischarField(field)) lines = 1; /* Reformat the Parameter String (replace spaces with zeros) ... but take case of possible text within quotes ! */ p += strscan(p, _SPACE_); while (*p) { if (isspace(*p)) *(p++) = EOS; else if (*p == '=') { if (*++p == '"') { ++p, p += strloc(p, '"'); if (*p) *(p++) = EOS; } p += strscan(p, _SPACE_); } else p += strloc(p, '='); } /* Open Subwindow if more than 1 line */ if (lines > 1) { field->value.window = OpenSubWindow(w, name, line, col, lines, cols, field->attr, 0, 0); field->attr = _NORMAL_; w = field->value.window; EnableArrows(w); } /* Determine now the bin type / factor */ field->bintype = field->type; /* Bin. default type */ field->binfactor = field->factor;/* Default Bin Factor */ if (field->bintype == _DTYPE_INT) /* Convert to Float */ { p = edit + strloc(edit, '.'); if (*p) { field->bintype = _DTYPE_DOUBLE; /* Convert to Float */ while (*++p == '9') field->binfactor *= 10.e0; } } /* Populate the Field with what exists on the Window: * and convert if necessary */ if (flen) TranslateWindow (w, field->string, --flen), field->string[flen] = EOS, tff_convert(field, field->string); SetPosition(w, old_pos); FIN: EXIT(flen); } /*=====================================================================*/ char *tff_parm(form, parm) /*++++++++++++ .PURPOSE Retrieve a parameter (form name=) in the current field .RETURNS Pointer to the text follwing the = sign / NULL if not found .REMARKS Parameter is of the form parm=value (NO BLANKS) ---------------*/ TFORM *form; /* IN: The form concerned */ char *parm; /* IN: The parameter to look for, e.g. `O=' */ { TFIELD *field; char *p, *pe; int len; ENTER("*tff_parm"); len = strlen(parm); field = form->fields + form->ifield; p = field->parm, pe = p + field->parm_size; while (p < pe) { if (oscomp(parm, p, len) == 0) break; p += 1 + strlen(p); } if (p < pe) { p += len; if (*p == '"') p++; } else p = NULL_PTR(char); EXITp(p); } /*=====================================================================*/ int tff_find(form, name) /*++++++++++++ .PURPOSE Retrieve a named field. .RETURNS The number of the named field / -1 if not found. .REMARKS Comparison is case sensitive. ---------------*/ TFORM *form; /* IN: The form concerned */ char *name; /* IN: The field to retrieve */ { TFIELD *field; int fn; ENTER("+tff_find"); for(field = form->fields, fn = form->nfields; --fn >= 0; field++) if (strcomp(name, field->name) == 0) break; if (fn >= 0) fn = field - form->fields; EXIT(fn); } /*=====================================================================*/ TFIELD *tff_ptr(form, name) /*++++++++++++ .PURPOSE Retrieve a named field pointer. .RETURNS The pointer to the found Field / NULL when not found .REMARKS Comparison is case sensitive. ---------------*/ TFORM *form; /* IN: The form concerned */ char *name; /* IN: The field to retrieve */ { TFIELD *field; int fn; ENTER("*tff_ptr"); for(field = form->fields, fn = form->nfields; --fn >= 0; field++) if (strcomp(name, field->name) == 0) break; if (fn < 0) field = NULL_PTR(TFIELD); EXIT_PTR(TFIELD, field); } /*=====================================================================*/ TF_FCT tff_aset(form, name, action) /*++++++++++++ .PURPOSE Associate an action (routine) to action field. .RETURNS The previous associated action / NULL if field not found or not action field. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ char *name; /* IN: The field to associate with action */ TF_FCT action; /* IN: Function called as action(form) */ { TFIELD *field; int fn; TF_FCT old_action; ENTER("*tff_aset"); old_action = (TF_FCT)0; fn = tff_find(form, name); /* Find Field */ if (fn >= 0) /* Field Found */ { field = form->fields + fn; if (isactionField(field)) old_action = field->value.action, field->value.action = action; else ERR_ED_STRING("Field is NOT an action: ", name); } else ERR_ED_STRING("Field not found: ", name); EXIT_CAST(TF_FCT, old_action); } /*=====================================================================*/ int tff_goto(form, fieldno) /*++++++++++++ .PURPOSE Move to a specified field. .RETURNS The old field number .REMARKS The attribute of the field is NOT set. ---------------*/ TFORM *form; /* IN: The form concerned */ int fieldno;/* IN: The field to go to */ { TFIELD *field; int old_field; ENTER("+tff_goto"); old_field = form->ifield; if ( (fieldno < 0) || (fieldno >= form->nfields)) form->ifield = form->nfields - 1; else form->ifield = fieldno; field = form->fields + form->ifield; CursorTo(form->window, field->pos[0], field->pos[1]); /* Put in place the address of the Current Field */ switch(field->type & 0xf) { case _DTYPE_INT: form->avalue = (int *)&(field->value.integer); break; case _DTYPE_DOUBLE: case _DTYPE_FLOAT: form->avalue = (int *)&(field->value.real); break; default: /* Assume String */ form->avalue = (int *)field->string; break; } EXIT(old_field); } /*=====================================================================*/ int tff_move(form, direction) /*++++++++++++ .PURPOSE Move to an adjacent field. .RETURNS The old field number .REMARKS The attribute of the field is NOT set. ---------------*/ TFORM *form; /* IN: The form concerned */ int direction; /* IN: _UP_ _DOWN_ etc. OR'ed with 16 \ if DISPLAY-ONLY must be taken into account*/ { TFIELD *pf; int i, imax, the_dir; short pos[2]; ENTER("+tff_move"); GetCursor(form->window, pos); i = form->ifield; pf = form->fields + i; imax = form->nfields - 1; the_dir = direction; while(1) /* For Ever ... */ { pf = form->fields + i; switch (the_dir&0xf) { case _LEFT_ : i--; break; default : case _RIGHT_ : i++; break; case _UP_ : /* Go first to previous line ... */ while ((i > 0) && (pf->pos[0] == pos[0])) pf--, i--; if (i <= 0) break; pos[0] = pf->pos[0]; while ((i > 0) && (pf->pos[0] == pos[0])) pf--, i--; if (pos[0] != pf->pos[0]) pf++, i++; goto case_vertical; case _DOWN_ : /* Go first to next line ... */ while ((i < imax) && (pf->pos[0] == pos[0])) pf++, i++; if (i >= imax) break; case_vertical: /* Move to the right until a field is found */ pos[0] = pf->pos[0]; /* Line */ while ((pf->pos[0] == pos[0]) && ((pf->pos[1] + pf->string_size) < pos[1])) i++, pf++; if (pf->pos[0] != pos[0]) pf--, i--; break; case _HOME_ : i = 0; break; } if (i < 0) i += form->nfields; if (i > imax) i = 0; i %= form->nfields; pf = form->fields + i; if_not(the_dir&0x10) break; if_not(pf->options & _FIELD_DISPLAY) break; /* Field cannot be modified by user... */ if(the_dir & 2) continue; /* Horizontal displacement */ if (i == 0) the_dir = (the_dir & ~0xf) |_RIGHT_; if (i == imax) the_dir = (the_dir & ~0xf) |_LEFT_; } EXIT(tff_goto(form, i)); } /*=====================================================================*/ int tff_cur(form) /*++++++++++++ .PURPOSE Retrieve the current field. .RETURNS The current field number (-1 if none) .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { return(form->ifield); } /*=====================================================================*/ TFIELD *tff_field(form, fieldno) /*++++++++++++ .PURPOSE Retrieve the specified field pointer. .RETURNS The current field pointer / NULL if Bad .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ int fieldno; /* IN: Number of Field */ { TFIELD *field; field = NULL_PTR(TFIELD); if ((fieldno >= 0) && (fieldno < form->nfields)) field = form->fields + fieldno; return(field); } /*=====================================================================*/ char *tff_name(form) /*++++++++++++ .PURPOSE Retrieve the current field name .RETURNS The current field name pointer. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; field = form->fields + form->ifield; return(field->name); } /*=====================================================================*/ char *tff_string(form) /*++++++++++++ .PURPOSE Retrieve the current field contents (string). .RETURNS The current field pointer. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; field = form->fields + form->ifield; return(field->string); } /*=====================================================================*/ long tff_ival(form) /*++++++++++++ .PURPOSE Retrieve the current field contents (integer). .RETURNS The integer value in the current field. .REMARKS Non-numeric data retun the NULL. ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; long value; field = form->fields + form->ifield; switch(field->type & 7) { case _DTYPE_INT: value = field->value.integer; break; case _DTYPE_DOUBLE: value = field->value.real; break; default: value = 0; break; } return(value); } /*=====================================================================*/ double tff_fval(form) /*++++++++++++ .PURPOSE Retrieve the current field contents (double). .RETURNS The floating-point value in the current field. .REMARKS Non-numeric data retun the NULL. ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; double value; field = form->fields + form->ifield; switch(field->type & 7) { case _DTYPE_INT: value = field->value.integer / field->binfactor; break; case _DTYPE_DOUBLE: value = field->value.real / field->binfactor; break; default: value = 0; break; } return(value); } /*=====================================================================*/ int tff_isnull(form) /*++++++++++++ .PURPOSE Tells if the current field has NULL value. .RETURNS 0 (not null) / 1 (null) .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; int value; field = form->fields + form->ifield; switch(field->type & 7) { case _DTYPE_INT: value = (field->value.intnull[0] == field->value.intnull[1]); break; default: value = 0; break; } return(value); } /*=====================================================================*/ char *tff_pic(form) /*++++++++++++ .PURPOSE Find the picture of the current field .RETURNS Pointer to current picture field. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; field = form->fields + form->ifield; return(field->picture); } /*=====================================================================*/ char *tff_dtype(form) /*++++++++++++ .PURPOSE Find the type of the current field .RETURNS Pointer to current type field. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; field = form->fields + form->ifield; return(field->parm); } /*=====================================================================*/ char *tff_note(form) /*++++++++++++ .PURPOSE Find the note associated to the current field .RETURNS Pointer to current type field. .REMARKS ---------------*/ TFORM *form; /* IN: The form concerned */ { TFIELD *field; field = form->fields + form->ifield; return(field->note); } /*=====================================================================*/ int tff_oclear(form, mask) /*++++++++++++ .PURPOSE Clear option in current field .RETURNS The status as it was before clearing. ------------------------------------------------------------------------*/ TFORM *form; /* IN: The form concerned */ int mask; /* IN: The mask */ { int i; TFIELD *field; field = form->fields + form->ifield; i = field->options & mask; field->options &= ~mask; return (i); } /*=====================================================================*/ int tff_oset(form, mask) /*++++++++++++ .PURPOSE Set options in form .RETURNS The status as it was before setting. ------------------------------------------------------------------------*/ TFORM *form; /* IN: The form concerned */ int mask; /* IN: The mask */ { int i; TFIELD *field; field = form->fields + form->ifield; i = field->options & mask; field->options |= mask; return (i); } /*=====================================================================*/ int tff_oget(form, mask) /*++++++++++++ .PURPOSE Get options in current field of form. .RETURNS 0 if option not present / not-zero if option present ------------------------------------------------------------------------*/ TFORM *form; /* IN: The form concerned */ int mask; /* IN: The mask */ { TFIELD *field; field = form->fields + form->ifield; return(field->options & mask); } /*=====================================================================*/ int tff_putnote (form, note) /*+++++++++++ .PURPOSE Insert or delete a note in the current field. .RETURNS OK / NOK. --------------*/ TFORM *form; /* IN: The field concerned */ char *note; /* IN: Note to insert (NULL to delete) */ { int len; TFIELD *field; ENTER("tff_note"); if (note) TRACE_ED_STRING("Note: ", note); if (note) if (*note == EOS) note = NULL_PTR(char); field = form->fields + form->ifield; if (note) { len = strlen(note) + 1; field->note = MEM_EXP(char, field->note, len); strcopy(field->note, note); } else { MEM_FREE(field->note); field->note = NULL_PTR(char); } EXIT(OK); }