📄 frm_driver.c
字号:
/**************************************************************************** * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//**************************************************************************** * Author: Juergen Pfeifer, 1995,1997 * ****************************************************************************/#include "form.priv.h"MODULE_ID("$Id: frm_driver.c,v 1.71 2005/10/01 19:42:40 tom Exp $")/*---------------------------------------------------------------------------- This is the core module of the form library. It contains the majority of the driver routines as well as the form_driver function. Essentially this module is nearly the whole library. This is because all the functions in this module depends on some others in the module, so it makes no sense to split them into separate files because they will always be linked together. The only acceptable concern is turnaround time for this module, but now we have all Pentiums or RISCs, so what! The driver routines are grouped into nine generic categories: a) Page Navigation ( all functions prefixed by PN_ ) The current page of the form is left and some new page is entered. b) Inter-Field Navigation ( all functions prefixed by FN_ ) The current field of the form is left and some new field is entered. c) Intra-Field Navigation ( all functions prefixed by IFN_ ) The current position in the current field is changed. d) Vertical Scrolling ( all functions prefixed by VSC_ ) Essentially this is a specialization of Intra-Field navigation. It has to check for a multi-line field. e) Horizontal Scrolling ( all functions prefixed by HSC_ ) Essentially this is a specialization of Intra-Field navigation. It has to check for a single-line field. f) Field Editing ( all functions prefixed by FE_ ) The content of the current field is changed g) Edit Mode requests ( all functions prefixed by EM_ ) Switching between insert and overlay mode h) Field-Validation requests ( all functions prefixed by FV_ ) Perform verifications of the field. i) Choice requests ( all functions prefixed by CR_ ) Requests to enumerate possible field values --------------------------------------------------------------------------*//*---------------------------------------------------------------------------- Some remarks on the placements of assert() macros : I use them only on "strategic" places, i.e. top level entries where I want to make sure that things are set correctly. Throughout subordinate routines I omit them mostly. --------------------------------------------------------------------------*//*Some options that may effect compatibility in behavior to SVr4 forms,but they are here to allow a more intuitive and user friendly behavior ofour form implementation. This doesn't affect the API, so we feel it isuncritical.The initial implementation tries to stay very close with the behaviorof the original SVr4 implementation, although in some areas it is quiteclear that this isn't the most appropriate way. As far as possible thissources will allow you to build a forms lib that behaves quite similarto SVr4, but now and in the future we will give you better options.Perhaps at some time we will make this configurable at runtime.*//* Implement a more user-friendly previous/next word behavior */#define FRIENDLY_PREV_NEXT_WORD (1)/* Fix the wrong behavior for forms with all fields inactive */#define FIX_FORM_INACTIVE_BUG (1)/* Allow dynamic field growth also when navigating past the end */#define GROW_IF_NAVIGATE (1)#if USE_WIDEC_SUPPORT#define myADDNSTR(w, s, n) wadd_wchnstr(w, s, n)#define myINSNSTR(w, s, n) wins_wchnstr(w, s, n)#define myINNSTR(w, s, n) fix_wchnstr(w, s, n)#define myWCWIDTH(w, y, x) cell_width(w, y, x)#else#define myADDNSTR(w, s, n) waddnstr(w, s, n)#define myINSNSTR(w, s, n) winsnstr(w, s, n)#define myINNSTR(w, s, n) winnstr(w, s, n)#define myWCWIDTH(w, y, x) 1#endif/*---------------------------------------------------------------------------- Forward references to some internally used static functions --------------------------------------------------------------------------*/static int Inter_Field_Navigation(int (*const fct) (FORM *), FORM *form);static int FN_Next_Field(FORM *form);static int FN_Previous_Field(FORM *form);static int FE_New_Line(FORM *);static int FE_Delete_Previous(FORM *);/*---------------------------------------------------------------------------- Macro Definitions. Some Remarks on that: I use the convention to use UPPERCASE for constants defined by Macros. If I provide a macro as a kind of inline routine to provide some logic, I use my Upper_Lower case style. --------------------------------------------------------------------------*//* Calculate the position of a single row in a field buffer */#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)/* Calculate start address for the fields buffer# N */#define Address_Of_Nth_Buffer(field,N) \ ((field)->buf + (N)*(1+Buffer_Length(field)))/* Calculate the start address of the row in the fields specified buffer# N */#define Address_Of_Row_In_Nth_Buffer(field,N,row) \ (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))/* Calculate the start address of the row in the fields primary buffer */#define Address_Of_Row_In_Buffer(field,row) \ Address_Of_Row_In_Nth_Buffer(field,0,row)/* Calculate the start address of the row in the forms current field buffer# N */#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \ Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)/* Calculate the start address of the row in the forms current field primary buffer */#define Address_Of_Current_Row_In_Buffer(form) \ Address_Of_Current_Row_In_Nth_Buffer(form,0)/* Calculate the address of the cursor in the forms current field primary buffer */#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \ (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)/* Calculate the address of the cursor in the forms current field buffer# N */#define Address_Of_Current_Position_In_Buffer(form) \ Address_Of_Current_Position_In_Nth_Buffer(form,0)/* Logic to decide whether or not a field is actually a field with vertical or horizontal scrolling */#define Is_Scroll_Field(field) \ (((field)->drows > (field)->rows) || \ ((field)->dcols > (field)->cols))/* Logic to decide whether or not a field needs to have an individual window instead of a derived window because it contains invisible parts. This is true for non-public fields and for scrollable fields. */#define Has_Invisible_Parts(field) \ (!((field)->opts & O_PUBLIC) || \ Is_Scroll_Field(field))/* Logic to decide whether or not a field needs justification */#define Justification_Allowed(field) \ (((field)->just != NO_JUSTIFICATION) && \ (Single_Line_Field(field)) && \ (((field)->dcols == (field)->cols) && \ ((field)->opts & O_STATIC)) )/* Logic to determine whether or not a dynamic field may still grow */#define Growable(field) ((field)->status & _MAY_GROW)/* Macro to set the attributes for a fields window */#define Set_Field_Window_Attributes(field,win) \( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \ wattrset((win),(field)->fore) )/* Logic to decide whether or not a field really appears on the form */#define Field_Really_Appears(field) \ ((field->form) &&\ (field->form->status & _POSTED) &&\ (field->opts & O_VISIBLE) &&\ (field->page == field->form->curpage))/* Logic to determine whether or not we are on the first position in the current field */#define First_Position_In_Current_Field(form) \ (((form)->currow==0) && ((form)->curcol==0))#define Minimum(a,b) (((a)<=(b)) ? (a) : (b))#define Maximum(a,b) (((a)>=(b)) ? (a) : (b))/*---------------------------------------------------------------------------- Useful constants --------------------------------------------------------------------------*/static FIELD_CELL myBLANK = BLANK;static FIELD_CELL myZEROS;#ifdef TRACEstatic voidcheck_pos(FORM *form, int lineno){ int y, x; if (form && form->w) { getyx(form->w, y, x); if (y != form->currow || x != form->curcol) { T(("CHECKPOS %s@%d have position %d,%d vs want %d,%d", __FILE__, lineno, y, x, form->currow, form->curcol)); } }}#define CHECKPOS(form) check_pos(form, __LINE__)#else#define CHECKPOS(form) /* nothing */#endif/*---------------------------------------------------------------------------- Wide-character special functions --------------------------------------------------------------------------*/#if USE_WIDEC_SUPPORT/* like winsnstr */static intwins_wchnstr(WINDOW *w, cchar_t *s, int n){ int code = ERR; int y, x; while (n-- > 0) { getyx(w, y, x); if ((code = wins_wch(w, s++)) != OK) break; if ((code = wmove(w, y, x + 1)) != OK) break; } return code;}/* win_wchnstr is inconsistent with winnstr, since it returns OK rather than * the number of items transferred. */static intfix_wchnstr(WINDOW *w, cchar_t *s, int n){ win_wchnstr(w, s, n); return n;}/* * Returns the column of the base of the given cell. */static intcell_base(WINDOW *win, int y, int x){ int result = x; while (LEGALYX(win, y, x)) { cchar_t *data = &(win->_line[y].text[x]); if (isWidecBase(CHDEREF(data)) || !isWidecExt(CHDEREF(data))) { result = x; break; } --x; } return result;}/* * Returns the number of columns needed for the given cell in a window. */static intcell_width(WINDOW *win, int y, int x){ int result = 1; if (LEGALYX(win, y, x)) { cchar_t *data = &(win->_line[y].text[x]); if (isWidecExt(CHDEREF(data))) { /* recur, providing the number of columns to the next character */ result = cell_width(win, y, x - 1); } else { result = wcwidth(CharOf(CHDEREF(data))); } } return result;}/* * There is no wide-character function such as wdel_wch(), so we must find * all of the cells that comprise a multi-column character and delete them * one-by-one. */static voiddelete_char(FORM *form){ int cells = cell_width(form->w, form->currow, form->curcol); form->curcol = cell_base(form->w, form->currow, form->curcol); wmove(form->w, form->currow, form->curcol); while (cells-- > 0) { wdelch(form->w); }}#define DeleteChar(form) delete_char(form)#else#define DeleteChar(form) \ wmove((form)->w, (form)->currow, (form)->curcol), \ wdelch((form)->w)#endif/*---------------------------------------------------------------------------| Facility : libnform| Function : static char *Get_Start_Of_Data(char * buf, int blen)|| Description : Return pointer to first non-blank position in buffer.| If buffer is empty return pointer to buffer itself.|| Return Values : Pointer to first non-blank position in buffer+--------------------------------------------------------------------------*/INLINE static FIELD_CELL *Get_Start_Of_Data(FIELD_CELL *buf, int blen){ FIELD_CELL *p = buf; FIELD_CELL *end = &buf[blen]; assert(buf && blen >= 0); while ((p < end) && ISBLANK(*p)) p++; return ((p == end) ? buf : p);}/*---------------------------------------------------------------------------| Facility : libnform| Function : static char *After_End_Of_Data(char * buf, int blen)|| Description : Return pointer after last non-blank position in buffer.| If buffer is empty, return pointer to buffer itself.|| Return Values : Pointer to position after last non-blank position in| buffer.+--------------------------------------------------------------------------*/INLINE static FIELD_CELL *After_End_Of_Data(FIELD_CELL *buf, int blen){ FIELD_CELL *p = &buf[blen]; assert(buf && blen >= 0); while ((p > buf) && ISBLANK(p[-1])) p--; return (p);}/*---------------------------------------------------------------------------| Facility : libnform| Function : static char *Get_First_Whitespace_Character(| char * buf, int blen)|| Description : Position to the first whitespace character.|| Return Values : Pointer to first whitespace character in buffer.+--------------------------------------------------------------------------*/INLINE static FIELD_CELL *Get_First_Whitespace_Character(FIELD_CELL *buf, int blen){ FIELD_CELL *p = buf; FIELD_CELL *end = &p[blen]; assert(buf && blen >= 0); while ((p < end) && !ISBLANK(*p)) p++; return ((p == end) ? buf : p);}/*---------------------------------------------------------------------------| Facility : libnform| Function : static char *After_Last_Whitespace_Character(| char * buf, int blen)|| Description : Get the position after the last whitespace character.|| Return Values : Pointer to position after last whitespace character in| buffer.+--------------------------------------------------------------------------*/INLINE static FIELD_CELL *After_Last_Whitespace_Character(FIELD_CELL *buf, int blen){ FIELD_CELL *p = &buf[blen];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -