?? frm_driver.c
字號(hào):
/**************************************************************************** * Copyright (c) 1998-2002,2003 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.45 2003/12/06 17:22:42 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)/*---------------------------------------------------------------------------- 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))/*---------------------------------------------------------------------------| 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 char *Get_Start_Of_Data(char * buf, int blen){ char *p = buf; char *end = &buf[blen]; assert(buf && blen>=0); while( (p < end) && is_blank(*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 char *After_End_Of_Data(char * buf,int blen){ char *p = &buf[blen]; assert(buf && blen>=0); while( (p>buf) && is_blank(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 char *Get_First_Whitespace_Character(char * buf, int blen){ char *p = buf; char *end = &p[blen]; assert(buf && blen>=0); while( (p < end) && !is_blank(*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 char *After_Last_Whitespace_Character(char * buf, int blen){ char *p = &buf[blen]; assert(buf && blen>=0); while( (p>buf) && !is_blank(p[-1]) ) p--; return( p );}/* Set this to 1 to use the div_t version. This is a good idea if your compiler has an intrinsic div() support. Unfortunately GNU-C has it not yet. N.B.: This only works if form->curcol follows immediately form->currow and both are of type int. */#define USE_DIV_T (0)/*---------------------------------------------------------------------------| Facility : libnform | Function : static void Adjust_Cursor_Position(| FORM * form, const char * pos)| | Description : Set current row and column of the form to values | corresponding to the buffer position.|| Return Values : -+--------------------------------------------------------------------------*/INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos){ FIELD *field; int idx; field = form->current; assert( pos >= field->buf && field->dcols > 0); idx = (int)( pos - field->buf );#if USE_DIV_T *((div_t *)&(form->currow)) = div(idx,field->dcols);#else form->currow = idx / field->dcols; form->curcol = idx - field->cols * form->currow;#endif if ( field->drows < form->currow ) form->currow = 0;}/*---------------------------------------------------------------------------| Facility : libnform | Function : static void Buffer_To_Window(| const FIELD * field,| WINDOW * win)| | Description : Copy the buffer to the window. If it is a multi-line| field, the buffer is split to the lines of the| window without any editing.|| Return Values : -+--------------------------------------------------------------------------*/static void Buffer_To_Window(const FIELD * field, WINDOW * win){ int width, height; int len; int row; char *pBuffer; assert(win && field); width = getmaxx(win); height = getmaxy(win); for(row=0, pBuffer=field->buf; row < height; row++, pBuffer += width ) { if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0) { wmove( win, row, 0 ); waddnstr( win, pBuffer, len ); } } }/*---------------------------------------------------------------------------| Facility : libnform | Function : static void Window_To_Buffer(| WINDOW * win,| FIELD * field)| | Description : Copy the content of the window into the buffer.| The multiple lines of a window are simply| concatenated into the buffer. Pad characters in| the window will be replaced by blanks in the buffer.|| Return Values : -+--------------------------------------------------------------------------*/static void Window_To_Buffer(WINDOW * win, FIELD * field){ int pad; int len = 0; char *p; int row, height; assert(win && field && field->buf ); pad = field->pad; p = field->buf; height = getmaxy(win); for(row=0; (row < height) && (row < field->drows); row++ ) { wmove( win, row, 0 ); len += winnstr( win, p+len, field->dcols ); } p[len] = '\0'; /* replace visual padding character by blanks in buffer */ if (pad != C_BLANK) { int i; for(i=0; i<len; i++, p++) { if (*p==pad) *p = C_BLANK; } }}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -