From a0e6850f820f09a03a1da1b4d78f9fafb3b9782f Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Tue, 12 Nov 2013 07:56:07 -0500 Subject: [PATCH] Importing lib/libform No Minix-specific changes needed. Change-Id: Ia8ddbdb57ac04dfb42d79c374b9e25b189f9dc3b --- distrib/sets/lists/minix/mi | 97 + lib/Makefile | 2 +- lib/libform/Makefile | 84 + lib/libform/driver.c | 467 ++++ lib/libform/field.c | 950 +++++++ lib/libform/field_types.c | 274 ++ lib/libform/form.c | 613 +++++ lib/libform/form.h | 382 +++ lib/libform/form_cursor.3 | 71 + lib/libform/form_data.3 | 75 + lib/libform/form_driver.3 | 226 ++ lib/libform/form_field.3 | 111 + lib/libform/form_field_attributes.3 | 100 + lib/libform/form_field_buffer.3 | 134 + lib/libform/form_field_info.3 | 89 + lib/libform/form_field_just.3 | 97 + lib/libform/form_field_new.3 | 117 + lib/libform/form_field_opts.3 | 157 ++ lib/libform/form_field_userptr.3 | 74 + lib/libform/form_field_validation.3 | 82 + lib/libform/form_fieldtype.3 | 150 ++ lib/libform/form_hook.3 | 116 + lib/libform/form_new.3 | 85 + lib/libform/form_new_page.3 | 75 + lib/libform/form_opts.3 | 104 + lib/libform/form_page.3 | 119 + lib/libform/form_post.3 | 85 + lib/libform/form_userptr.3 | 74 + lib/libform/form_win.3 | 109 + lib/libform/forms.3 | 235 ++ lib/libform/gdbinit | 20 + lib/libform/internals.c | 3651 +++++++++++++++++++++++++++ lib/libform/internals.h | 151 ++ lib/libform/post.c | 119 + lib/libform/shlib_version | 5 + lib/libform/std_header.c | 34 + lib/libform/type_alnum.c | 176 ++ lib/libform/type_alpha.c | 180 ++ lib/libform/type_enum.c | 369 +++ lib/libform/type_integer.c | 185 ++ lib/libform/type_ipv4.c | 211 ++ lib/libform/type_ipv6.c | 123 + lib/libform/type_numeric.c | 220 ++ lib/libform/type_regex.c | 129 + releasetools/nbsd_ports | 1 + 45 files changed, 10927 insertions(+), 1 deletion(-) create mode 100644 lib/libform/Makefile create mode 100644 lib/libform/driver.c create mode 100644 lib/libform/field.c create mode 100644 lib/libform/field_types.c create mode 100644 lib/libform/form.c create mode 100644 lib/libform/form.h create mode 100644 lib/libform/form_cursor.3 create mode 100644 lib/libform/form_data.3 create mode 100644 lib/libform/form_driver.3 create mode 100644 lib/libform/form_field.3 create mode 100644 lib/libform/form_field_attributes.3 create mode 100644 lib/libform/form_field_buffer.3 create mode 100644 lib/libform/form_field_info.3 create mode 100644 lib/libform/form_field_just.3 create mode 100644 lib/libform/form_field_new.3 create mode 100644 lib/libform/form_field_opts.3 create mode 100644 lib/libform/form_field_userptr.3 create mode 100644 lib/libform/form_field_validation.3 create mode 100644 lib/libform/form_fieldtype.3 create mode 100644 lib/libform/form_hook.3 create mode 100644 lib/libform/form_new.3 create mode 100644 lib/libform/form_new_page.3 create mode 100644 lib/libform/form_opts.3 create mode 100644 lib/libform/form_page.3 create mode 100644 lib/libform/form_post.3 create mode 100644 lib/libform/form_userptr.3 create mode 100644 lib/libform/form_win.3 create mode 100644 lib/libform/forms.3 create mode 100644 lib/libform/gdbinit create mode 100644 lib/libform/internals.c create mode 100644 lib/libform/internals.h create mode 100644 lib/libform/post.c create mode 100644 lib/libform/shlib_version create mode 100644 lib/libform/std_header.c create mode 100644 lib/libform/type_alnum.c create mode 100644 lib/libform/type_alpha.c create mode 100644 lib/libform/type_enum.c create mode 100644 lib/libform/type_integer.c create mode 100644 lib/libform/type_ipv4.c create mode 100644 lib/libform/type_ipv6.c create mode 100644 lib/libform/type_numeric.c create mode 100644 lib/libform/type_regex.c diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index caa2f4353..883401ccb 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -677,6 +677,7 @@ ./usr/include/float.h minix-sys ./usr/include/fmtmsg.h minix-sys ./usr/include/fnmatch.h minix-sys +./usr/include/form.h minix-sys ./usr/include/fstab.h minix-sys ./usr/include/fts.h minix-sys ./usr/include/ftw.h minix-sys @@ -1658,6 +1659,11 @@ ./usr/lib/libexec_pic.a minix-sys ./usr/lib/libfetch.a minix-sys ./usr/lib/libfl.a minix-sys +./usr/lib/libform.a minix-sys +./usr/lib/libform.so minix-sys +./usr/lib/libform.so.6 minix-sys +./usr/lib/libform.so.6.0 minix-sys +./usr/lib/libform_pic.a minix-sys ./usr/lib/libgcc.a minix-sys gcc=45 ./usr/lib/libgcc_eh.a minix-sys gcccmds ./usr/lib/libgcc_s.a minix-sys gcccmds @@ -2699,6 +2705,7 @@ ./usr/man/man3/ctime_r.3 minix-sys ./usr/man/man3/ctime_rz.3 minix-sys ./usr/man/man3/ctype.3 minix-sys +./usr/man/man3/current_field.3 minix-sys ./usr/man/man3/current_item.3 minix-sys ./usr/man/man3/curses.3 minix-sys ./usr/man/man3/curses_addch.3 minix-sys @@ -2737,6 +2744,8 @@ ./usr/man/man3/curses_window.3 minix-sys ./usr/man/man3/curs_set.3 minix-sys ./usr/man/man3/daemon.3 minix-sys +./usr/man/man3/data_ahead.3 minix-sys +./usr/man/man3/data_behind.3 minix-sys ./usr/man/man3/daylight.3 minix-sys ./usr/man/man3/db.3 minix-sys ./usr/man/man3/dbm_clearerr.3 minix-sys @@ -2772,7 +2781,9 @@ ./usr/man/man3/doupdate.3 minix-sys ./usr/man/man3/dprintf.3 minix-sys ./usr/man/man3/drand48.3 minix-sys +./usr/man/man3/dup_field.3 minix-sys ./usr/man/man3/dupwin.3 minix-sys +./usr/man/man3/dynamic_field_info.3 minix-sys ./usr/man/man3/easprintf.3 minix-sys ./usr/man/man3/ecalloc.3 minix-sys ./usr/man/man3/echo.3 minix-sys @@ -2944,6 +2955,23 @@ ./usr/man/man3/fgetwc.3 minix-sys ./usr/man/man3/fgetwln.3 minix-sys ./usr/man/man3/fgetws.3 minix-sys +./usr/man/man3/field_arg.3 minix-sys +./usr/man/man3/field_back.3 minix-sys +./usr/man/man3/field_buffer.3 minix-sys +./usr/man/man3/field_count.3 minix-sys +./usr/man/man3/field_fore.3 minix-sys +./usr/man/man3/field_index.3 minix-sys +./usr/man/man3/field_info.3 minix-sys +./usr/man/man3/field_init.3 minix-sys +./usr/man/man3/field_just.3 minix-sys +./usr/man/man3/field_opts.3 minix-sys +./usr/man/man3/field_opts_off.3 minix-sys +./usr/man/man3/field_opts_on.3 minix-sys +./usr/man/man3/field_pad.3 minix-sys +./usr/man/man3/field_status.3 minix-sys +./usr/man/man3/field_term.3 minix-sys +./usr/man/man3/field_type.3 minix-sys +./usr/man/man3/field_userptr.3 minix-sys ./usr/man/man3/fileno.3 minix-sys ./usr/man/man3/finite.3 minix-sys ./usr/man/man3/finitef.3 minix-sys @@ -2968,6 +2996,36 @@ ./usr/man/man3/fnmatch.3 minix-sys ./usr/man/man3/fopen.3 minix-sys ./usr/man/man3/forkpty.3 minix-sys +./usr/man/man3/form.3 minix-sys +./usr/man/man3/form_cursor.3 minix-sys +./usr/man/man3/form_data.3 minix-sys +./usr/man/man3/form_driver.3 minix-sys +./usr/man/man3/form_field.3 minix-sys +./usr/man/man3/form_field_attributes.3 minix-sys +./usr/man/man3/form_field_buffer.3 minix-sys +./usr/man/man3/form_field_info.3 minix-sys +./usr/man/man3/form_field_just.3 minix-sys +./usr/man/man3/form_field_new.3 minix-sys +./usr/man/man3/form_field_opts.3 minix-sys +./usr/man/man3/form_field_userptr.3 minix-sys +./usr/man/man3/form_field_validation.3 minix-sys +./usr/man/man3/form_fields.3 minix-sys +./usr/man/man3/form_fieldtype.3 minix-sys +./usr/man/man3/form_hook.3 minix-sys +./usr/man/man3/form_init.3 minix-sys +./usr/man/man3/form_max_page.3 minix-sys +./usr/man/man3/form_new.3 minix-sys +./usr/man/man3/form_new_page.3 minix-sys +./usr/man/man3/form_opts.3 minix-sys +./usr/man/man3/form_opts_off.3 minix-sys +./usr/man/man3/form_opts_on.3 minix-sys +./usr/man/man3/form_page.3 minix-sys +./usr/man/man3/form_post.3 minix-sys +./usr/man/man3/form_sub.3 minix-sys +./usr/man/man3/form_term.3 minix-sys +./usr/man/man3/form_userptr.3 minix-sys +./usr/man/man3/form_win.3 minix-sys +./usr/man/man3/forms.3 minix-sys ./usr/man/man3/fparseln.3 minix-sys ./usr/man/man3/fpclassify.3 minix-sys ./usr/man/man3/fpgetmask.3 minix-sys @@ -2988,6 +3046,9 @@ ./usr/man/man3/fputws.3 minix-sys ./usr/man/man3/fread.3 minix-sys ./usr/man/man3/free.3 minix-sys +./usr/man/man3/free_field.3 minix-sys +./usr/man/man3/free_fieldtype.3 minix-sys +./usr/man/man3/free_form.3 minix-sys ./usr/man/man3/free_item.3 minix-sys ./usr/man/man3/free_menu.3 minix-sys ./usr/man/man3/freeaddrinfo.3 minix-sys @@ -3348,6 +3409,8 @@ ./usr/man/man3/libmagic.3 minix-sys ./usr/man/man3/link_addr.3 minix-sys ./usr/man/man3/linkaddr.3 minix-sys +./usr/man/man3/link_field.3 minix-sys +./usr/man/man3/link_fieldtype.3 minix-sys ./usr/man/man3/link_ntoa.3 minix-sys ./usr/man/man3/linkntoa.3 minix-sys ./usr/man/man3/llabs.3 minix-sys @@ -3493,6 +3556,7 @@ ./usr/man/man3/mktime_z.3 minix-sys ./usr/man/man3/modf.3 minix-sys ./usr/man/man3/move.3 minix-sys +./usr/man/man3/move_field.3 minix-sys ./usr/man/man3/mpool.3 minix-sys ./usr/man/man3/mpool_close.3 minix-sys ./usr/man/man3/mpool_filter.3 minix-sys @@ -3543,8 +3607,12 @@ ./usr/man/man3/napms.3 minix-sys ./usr/man/man3/ndbm.3 minix-sys ./usr/man/man3/network.3 minix-sys +./usr/man/man3/new_field.3 minix-sys +./usr/man/man3/new_fieldtype.3 minix-sys +./usr/man/man3/new_form.3 minix-sys ./usr/man/man3/new_item.3 minix-sys ./usr/man/man3/new_menu.3 minix-sys +./usr/man/man3/new_page.3 minix-sys ./usr/man/man3/newpad.3 minix-sys ./usr/man/man3/newterm.3 minix-sys ./usr/man/man3/newwin.3 minix-sys @@ -3595,6 +3663,7 @@ ./usr/man/man3/popcountl.3 minix-sys ./usr/man/man3/popcountll.3 minix-sys ./usr/man/man3/popen.3 minix-sys +./usr/man/man3/pos_form_cursor.3 minix-sys ./usr/man/man3/pos_menu_cursor.3 minix-sys ./usr/man/man3/posix2time.3 minix-sys ./usr/man/man3/posix2time_z.3 minix-sys @@ -3621,6 +3690,7 @@ ./usr/man/man3/posix_spawn_file_actions_destroy.3 minix-sys ./usr/man/man3/posix_spawn_file_actions_init.3 minix-sys ./usr/man/man3/posix_spawnp.3 minix-sys +./usr/man/man3/post_form.3 minix-sys ./usr/man/man3/post_menu.3 minix-sys ./usr/man/man3/pow.3 minix-sys ./usr/man/man3/powf.3 minix-sys @@ -3916,6 +3986,7 @@ ./usr/man/man3/scalbf.3 minix-sys ./usr/man/man3/scalbn.3 minix-sys ./usr/man/man3/scalbnf.3 minix-sys +./usr/man/man3/scale_form.3 minix-sys ./usr/man/man3/scale_menu.3 minix-sys ./usr/man/man3/scandir.3 minix-sys ./usr/man/man3/scanf.3 minix-sys @@ -3926,11 +3997,35 @@ ./usr/man/man3/secure_path.3 minix-sys ./usr/man/man3/seed48.3 minix-sys ./usr/man/man3/seekdir.3 minix-sys +./usr/man/man3/set_current_field.3 minix-sys ./usr/man/man3/set_current_item.3 minix-sys +./usr/man/man3/set_field_back.3 minix-sys +./usr/man/man3/set_field_buffer.3 minix-sys +./usr/man/man3/set_field_fore.3 minix-sys +./usr/man/man3/set_field_init.3 minix-sys +./usr/man/man3/set_field_just.3 minix-sys +./usr/man/man3/set_field_opts.3 minix-sys +./usr/man/man3/set_field_pad.3 minix-sys +./usr/man/man3/set_field_printf.3 minix-sys +./usr/man/man3/set_field_status.3 minix-sys +./usr/man/man3/set_field_term.3 minix-sys +./usr/man/man3/set_field_type.3 minix-sys +./usr/man/man3/set_field_userptr.3 minix-sys +./usr/man/man3/set_fieldtype_arg.3 minix-sys +./usr/man/man3/set_fieldtype_choice.3 minix-sys +./usr/man/man3/set_form_fields.3 minix-sys +./usr/man/man3/set_form_init.3 minix-sys +./usr/man/man3/set_form_opts.3 minix-sys +./usr/man/man3/set_form_page.3 minix-sys +./usr/man/man3/set_form_sub.3 minix-sys +./usr/man/man3/set_form_term.3 minix-sys +./usr/man/man3/set_form_userptr.3 minix-sys +./usr/man/man3/set_form_win.3 minix-sys ./usr/man/man3/set_item_init.3 minix-sys ./usr/man/man3/set_item_term.3 minix-sys ./usr/man/man3/set_item_userptr.3 minix-sys ./usr/man/man3/set_item_value.3 minix-sys +./usr/man/man3/set_max_field.3 minix-sys ./usr/man/man3/set_menu_back.3 minix-sys ./usr/man/man3/set_menu_fore.3 minix-sys ./usr/man/man3/set_menu_format.3 minix-sys @@ -3945,6 +4040,7 @@ ./usr/man/man3/set_menu_unmark.3 minix-sys ./usr/man/man3/set_menu_userptr.3 minix-sys ./usr/man/man3/set_menu_win.3 minix-sys +./usr/man/man3/set_new_page.3 minix-sys ./usr/man/man3/set_top_row.3 minix-sys ./usr/man/man3/setbuf.3 minix-sys ./usr/man/man3/setbuffer.3 minix-sys @@ -4260,6 +4356,7 @@ ./usr/man/man3/ungetch.3 minix-sys ./usr/man/man3/ungetwc.3 minix-sys ./usr/man/man3/unlockpt.3 minix-sys +./usr/man/man3/unpost_form.3 minix-sys ./usr/man/man3/unpost_menu.3 minix-sys ./usr/man/man3/unsetenv.3 minix-sys ./usr/man/man3/untouchwin.3 minix-sys diff --git a/lib/Makefile b/lib/Makefile index f8bcb51b7..ee718c68d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -179,7 +179,7 @@ SUBDIR+= ../external/bsd/lutok/lib # depends on lua and libstdc++ .endif .endif # (defined(__MINIX) && ${MKGCCCMDS} == "yes") -#SUBDIR+= libform # depends on libcurses +SUBDIR+= libform # depends on libcurses SUBDIR+= libmenu # depends on libcurses #SUBDIR+= libradius # depends on libcrypto if (${MKCRYPTO} != "no") .if (${MKRUMP} != "no") diff --git a/lib/libform/Makefile b/lib/libform/Makefile new file mode 100644 index 000000000..f919518bf --- /dev/null +++ b/lib/libform/Makefile @@ -0,0 +1,84 @@ +# $NetBSD: Makefile,v 1.10 2012/03/21 05:38:49 matt Exp $ +# + +WARNS= 2 + +CPPFLAGS+=-I${.CURDIR} +.if defined(DEBUG_FORMS) +CFLAGS+=-gdwarf-2 +CPPFLAGS+=-DDEBUG +LDFLAGS+=-g +.endif +LIB= form + +LIBDPLIBS+= curses ${.CURDIR}/../libcurses + +SRCS= driver.c field_types.c internals.c field.c form.c post.c type_alnum.c \ + type_alpha.c type_integer.c type_numeric.c type_enum.c type_regex.c \ + type_ipv4.c type_ipv6.c +MAN= form_cursor.3 form_data.3 form_driver.3 form_field.3 \ + form_field_attributes.3 form_field_buffer.3 form_field_info.3 \ + form_field_just.3 form_field_new.3 form_field_opts.3 \ + form_field_userptr.3 form_field_validation.3 form_fieldtype.3 \ + form_hook.3 form_new.3 form_new_page.3 form_opts.3 form_page.3 \ + form_post.3 form_userptr.3 form_win.3 forms.3 +MLINKS+= forms.3 form.3 form_page.3 current_field.3 \ + form_data.3 data_ahead.3 form_field_new.3 dup_field.3 \ + form_field_info.3 dynamic_field_info.3 \ + form_page.3 current_field.3 form_data.3 data_ahead.3 \ + form_data.3 data_behind.3 form_field_new.3 dup_field.3 \ + form_field_info.3 dynamic_field_info.3 \ + form_field_validation.3 field_arg.3 \ + form_field_attributes.3 field_back.3 \ + form_field_buffer.3 field_buffer.3 \ + form_field.3 field_count.3 \ + form_field_attributes.3 field_fore.3 \ + form_page.3 field_index.3 form_field_info.3 field_info.3 \ + form_hook.3 field_init.3 form_field_just.3 field_just.3 \ + form_field_opts.3 field_opts.3 \ + form_field_opts.3 field_opts_off.3 \ + form_field_opts.3 field_opts_on.3 \ + form_field_attributes.3 field_pad.3 \ + form_field_buffer.3 field_status.3 form_hook.3 field_term.3 \ + form_field_validation.3 field_type.3 \ + form_field_userptr.3 field_userptr.3 \ + form_field.3 form_fields.3 \ + form_hook.3 form_init.3 form_page.3 form_max_page.3 \ + form_opts.3 form_opts_off.3 \ + form_opts.3 form_opts_on.3 \ + form_win.3 form_sub.3 form_hook.3 form_term.3 \ + form_field_new.3 free_field.3 \ + form_fieldtype.3 free_fieldtype.3 \ + form_new.3 free_form.3 form_field_new.3 link_field.3 \ + form_fieldtype.3 link_fieldtype.3 form_field.3 move_field.3 \ + form_field_new.3 new_field.3 \ + form_fieldtype.3 new_fieldtype.3 \ + form_new.3 new_form.3 form_new_page.3 new_page.3 \ + form_cursor.3 pos_form_cursor.3 form_post.3 post_form.3 \ + form_win.3 scale_form.3 form_page.3 set_current_field.3 \ + form_field_attributes.3 set_field_back.3 \ + form_field_buffer.3 set_field_buffer.3 \ + form_field_attributes.3 set_field_fore.3 \ + form_hook.3 set_field_init.3 \ + form_field_just.3 set_field_just.3 \ + form_field_opts.3 set_field_opts.3 \ + form_field_attributes.3 set_field_pad.3 \ + form_field_buffer.3 set_field_printf.3 \ + form_field_buffer.3 set_field_status.3 \ + form_hook.3 set_field_term.3 \ + form_field_validation.3 set_field_type.3 \ + form_field_userptr.3 set_field_userptr.3 \ + form_fieldtype.3 set_fieldtype_arg.3 \ + form_fieldtype.3 set_fieldtype_choice.3 \ + form_field.3 set_form_fields.3 \ + form_hook.3 set_form_init.3 form_opts.3 set_form_opts.3 \ + form_page.3 set_form_page.3 form_win.3 set_form_sub.3 \ + form_hook.3 set_form_term.3 form_userptr.3 set_form_userptr.3 \ + form_win.3 set_form_win.3 form_field_buffer.3 set_max_field.3 \ + form_new_page.3 set_new_page.3 form_post.3 unpost_form.3 + +INCS= form.h +INCSDIR=/usr/include + +.include +.include diff --git a/lib/libform/driver.c b/lib/libform/driver.c new file mode 100644 index 000000000..2dbc02962 --- /dev/null +++ b/lib/libform/driver.c @@ -0,0 +1,467 @@ +/* $NetBSD: driver.c,v 1.17 2010/02/03 15:34:43 roy Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: driver.c,v 1.17 2010/02/03 15:34:43 roy Exp $"); + +#include +#include "form.h" +#include "internals.h" + +static int +traverse_form_links(FORM *form, int direction); + +/* + * Traverse the links of the current field in the given direction until + * either a active & visible field is found or we return to the current + * field. Direction is the REQ_{LEFT,RIGHT,UP,DOWN}_FIELD driver commands. + * The function returns E_OK if a valid field is found, E_REQUEST_DENIED + * otherwise. + */ +static int +traverse_form_links(FORM *form, int direction) +{ + unsigned idx; + + idx = form->cur_field; + + do { + switch (direction) { + case REQ_LEFT_FIELD: + if (form->fields[idx]->left == NULL) + return E_REQUEST_DENIED; + idx = form->fields[idx]->left->index; + break; + + case REQ_RIGHT_FIELD: + if (form->fields[idx]->right == NULL) + return E_REQUEST_DENIED; + idx = form->fields[idx]->right->index; + break; + + case REQ_UP_FIELD: + if (form->fields[idx]->up == NULL) + return E_REQUEST_DENIED; + idx = form->fields[idx]->up->index; + break; + + case REQ_DOWN_FIELD: + if (form->fields[idx]->down == NULL) + return E_REQUEST_DENIED; + idx = form->fields[idx]->down->index; + break; + + default: + return E_REQUEST_DENIED; + } + + if ((form->fields[idx]->opts & (O_ACTIVE | O_VISIBLE)) + == (O_ACTIVE | O_VISIBLE)) { + form->cur_field = idx; + return E_OK; + } + } while (idx != form->cur_field); + + return E_REQUEST_DENIED; +} + +int +form_driver(FORM *form, int c) +{ + FIELD *fieldp; + int update_page, update_field, old_field, old_page, status; + int start_field; + unsigned int pos; + + if (form == NULL) + return E_BAD_ARGUMENT; + + if ((form->fields == NULL) || (*(form->fields) == NULL)) + return E_INVALID_FIELD; + + if (form->posted != 1) + return E_NOT_POSTED; + + if (form->in_init == 1) + return E_BAD_STATE; + + + old_field = start_field = form->cur_field; + fieldp = form->fields[form->cur_field]; + update_page = update_field = 0; + status = E_OK; + + if (c < REQ_MIN_REQUEST) { + if (isprint(c) || isblank(c)) { + do { + pos = fieldp->start_char + fieldp->row_xpos; + + /* check if we are allowed to edit this field */ + if ((fieldp->opts & O_EDIT) != O_EDIT) + return E_REQUEST_DENIED; + + if ((status = + (_formi_add_char(fieldp, pos, c))) + == E_REQUEST_DENIED) { + + /* + * Need to check here if we + * want to autoskip. we + * call the form driver + * recursively to pos us on + * the next field and then + * we loop back to ensure + * the next field selected + * can have data added to it + */ + if ((fieldp->opts & O_AUTOSKIP) + != O_AUTOSKIP) + return E_REQUEST_DENIED; + status = form_driver(form, + REQ_NEXT_FIELD); + if (status != E_OK) + return status; + + /* + * check if we have looped + * around all the fields. + * This can easily happen if + * all the fields are full. + */ + if (start_field == form->cur_field) + return E_REQUEST_DENIED; + + old_field = form->cur_field; + fieldp = form->fields[form->cur_field]; + status = _formi_add_char(fieldp, + fieldp->start_char + + fieldp->cursor_xpos, + c); + } else if (status == E_INVALID_FIELD) + /* char failed validation, just + * return the status. + */ + return status; + else if (status == E_NO_ROOM) + /* we will get this if the line + * wrapping fails. Deny the + * request. + */ + return E_REQUEST_DENIED; + } + while (status != E_OK); + update_field = (status == E_OK); + } else + return E_REQUEST_DENIED; + } else { + if (c > REQ_MAX_COMMAND) + return E_UNKNOWN_COMMAND; + + if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) { + /* first check the field we are in is ok */ + if (_formi_validate_field(form) != E_OK) + return E_INVALID_FIELD; + + if (form->field_term != NULL) + form->field_term(form); + + /* + * if we have a page movement then the form term + * needs to be called too + */ + if ((c <= REQ_LAST_PAGE) && (form->form_term != NULL)) + form->form_term(form); + } + + + switch (c) { + case REQ_NEXT_PAGE: + if (form->page < form->max_page) { + old_page = form->page; + form->page++; + update_page = 1; + if (_formi_pos_first_field(form) != E_OK) { + form->page = old_page; + status = E_REQUEST_DENIED; + } + } else + status = E_REQUEST_DENIED; + break; + + case REQ_PREV_PAGE: + if (form->page > 0) { + old_page = form->page; + form->page--; + update_page = 1; + if (_formi_pos_first_field(form) != E_OK) { + form->page = old_page; + status = E_REQUEST_DENIED; + } + } else + status = E_REQUEST_DENIED; + break; + + case REQ_FIRST_PAGE: + old_page = form->page; + form->page = 0; + update_page = 1; + if (_formi_pos_first_field(form) != E_OK) { + form->page = old_page; + status = E_REQUEST_DENIED; + } + break; + + case REQ_LAST_PAGE: + old_page = form->page; + form->page = form->max_page - 1; + update_page = 1; + if (_formi_pos_first_field(form) != E_OK) { + form->page = old_page; + status = E_REQUEST_DENIED; + } + break; + + case REQ_NEXT_FIELD: + status = _formi_pos_new_field(form, _FORMI_FORWARD, + FALSE); + update_field = 1; + break; + + case REQ_PREV_FIELD: + status = _formi_pos_new_field(form, _FORMI_BACKWARD, + FALSE); + update_field = 1; + break; + + case REQ_FIRST_FIELD: + form->cur_field = 0; + update_field = 1; + break; + + case REQ_LAST_FIELD: + form->cur_field = form->field_count - 1; + update_field = 1; + break; + + case REQ_SNEXT_FIELD: + status = _formi_pos_new_field(form, _FORMI_FORWARD, + TRUE); + update_field = 1; + break; + + case REQ_SPREV_FIELD: + status = _formi_pos_new_field(form, _FORMI_BACKWARD, + TRUE); + update_field = 1; + break; + + case REQ_SFIRST_FIELD: + fieldp = CIRCLEQ_FIRST(&form->sorted_fields); + form->cur_field = fieldp->index; + update_field = 1; + break; + + case REQ_SLAST_FIELD: + fieldp = CIRCLEQ_LAST(&form->sorted_fields); + form->cur_field = fieldp->index; + update_field = 1; + break; + + /* + * The up, down, left and right field traversals + * are rolled up into a single function, allow a + * fall through to that function. + */ + case REQ_LEFT_FIELD: + case REQ_RIGHT_FIELD: + case REQ_UP_FIELD: + case REQ_DOWN_FIELD: + status = traverse_form_links(form, c); + update_field = 1; + break; + + /* the following commands modify the buffer, check if + this is allowed first before falling through. */ + + case REQ_DEL_PREV: + /* + * need to check for the overloading of this + * request. If overload flag set and we are + * at the start of field this request turns + * into a previous field request. Otherwise + * fallthrough to the field handler. + */ + if ((form->opts & O_BS_OVERLOAD) == O_BS_OVERLOAD) { + if ((fieldp->start_char == 0) && + (fieldp->start_line == 0) && + (fieldp->row_xpos == 0)) { + update_field = + _formi_manipulate_field(form, + REQ_PREV_FIELD); + break; + } + } + + /* FALLTHROUGH */ + case REQ_NEW_LINE: + /* + * need to check for the overloading of this + * request. If overload flag set and we are + * at the start of field this request turns + * into a next field request. Otherwise + * fallthrough to the field handler. + */ + if ((form->opts & O_NL_OVERLOAD) == O_NL_OVERLOAD) { + if ((fieldp->start_char == 0) && + (fieldp->start_line == 0) && + (fieldp->row_xpos == 0)) { + update_field = + _formi_manipulate_field(form, + REQ_NEXT_FIELD); + break; + } + } + + /* FALLTHROUGH */ + case REQ_INS_CHAR: + case REQ_INS_LINE: + case REQ_DEL_CHAR: + case REQ_DEL_LINE: + case REQ_DEL_WORD: + case REQ_CLR_EOL: + case REQ_CLR_EOF: + case REQ_CLR_FIELD: + case REQ_OVL_MODE: + case REQ_INS_MODE: + /* check if we are allowed to edit the field and fall + * through if we are. + */ + if ((form->fields[form->cur_field]->opts & O_EDIT) != O_EDIT) + return E_REQUEST_DENIED; + + /* the following manipulate the field contents, bundle + them into one function.... */ + /* FALLTHROUGH */ + case REQ_NEXT_CHAR: + case REQ_PREV_CHAR: + case REQ_NEXT_LINE: + case REQ_PREV_LINE: + case REQ_NEXT_WORD: + case REQ_PREV_WORD: + case REQ_BEG_FIELD: + case REQ_END_FIELD: + case REQ_BEG_LINE: + case REQ_END_LINE: + case REQ_LEFT_CHAR: + case REQ_RIGHT_CHAR: + case REQ_UP_CHAR: + case REQ_DOWN_CHAR: + case REQ_SCR_FLINE: + case REQ_SCR_BLINE: + case REQ_SCR_FPAGE: + case REQ_SCR_BPAGE: + case REQ_SCR_FHPAGE: + case REQ_SCR_BHPAGE: + case REQ_SCR_FCHAR: + case REQ_SCR_BCHAR: + case REQ_SCR_HFLINE: + case REQ_SCR_HBLINE: + case REQ_SCR_HFHALF: + case REQ_SCR_HBHALF: + update_field = _formi_manipulate_field(form, c); + break; + + case REQ_VALIDATION: + return _formi_validate_field(form); + /* NOTREACHED */ + break; + + case REQ_PREV_CHOICE: + case REQ_NEXT_CHOICE: + update_field = _formi_field_choice(form, c); + /* reinit the cursor pos just in case */ + if (update_field == 1) { + _formi_init_field_xpos(fieldp); + fieldp->row_xpos = 0; + } + break; + + default: /* should not need to do this, but.... */ + return E_UNKNOWN_COMMAND; + /* NOTREACHED */ + break; + } + } + + /* call the field and form init functions if required. */ + if ((c >= REQ_NEXT_PAGE) && (c <= REQ_DOWN_FIELD)) { + if (form->field_init != NULL) + form->field_init(form); + + /* + * if we have a page movement then the form init + * needs to be called too + */ + if ((c <= REQ_LAST_PAGE) && (form->form_init != NULL)) + form->form_init(form); + + /* + * if there was an error just return now... + */ + if (status != E_OK) + return status; + + /* if we have no error, reset the various offsets */ + fieldp = form->fields[form->cur_field]; + fieldp->start_char = 0; + fieldp->start_line = fieldp->alines; + fieldp->cur_line = fieldp->alines; + fieldp->row_xpos = 0; + fieldp->cursor_ypos = 0; + _formi_init_field_xpos(fieldp); + } + + if (update_field < 0) + return update_field; + + if (update_field == 1) + update_page |= _formi_update_field(form, old_field); + + if (update_page == 1) + _formi_draw_page(form); + + pos_form_cursor(form); + + if ((update_page == 1) || (update_field == 1)) + wrefresh(form->scrwin); + + return E_OK; +} diff --git a/lib/libform/field.c b/lib/libform/field.c new file mode 100644 index 000000000..185ed648f --- /dev/null +++ b/lib/libform/field.c @@ -0,0 +1,950 @@ +/* $NetBSD: field.c,v 1.25 2010/02/03 15:34:43 roy Exp $ */ +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: field.c,v 1.25 2010/02/03 15:34:43 roy Exp $"); + +#include +#include +#include +#include +#include "internals.h" + +extern FORM _formi_default_form; + +FIELD _formi_default_field = { + 0, /* rows in the field */ + 0, /* columns in the field */ + 0, /* dynamic rows */ + 0, /* dynamic columns */ + 0, /* maximum growth */ + 0, /* starting row in the form subwindow */ + 0, /* starting column in the form subwindow */ + 0, /* number of off screen rows */ + 0, /* index of this field in form fields array. */ + 0, /* number of buffers associated with this field */ + FALSE, /* set to true if buffer 0 has changed. */ + NO_JUSTIFICATION, /* justification style of the field */ + FALSE, /* set to true if field is in overlay mode */ + NULL, /* pointer to the current line cursor is on */ + 0, /* starting char in string (horiz scroll) */ + NULL, /* starting line in field (vert scroll) */ + 0, /* number of rows actually used in field */ + 0, /* actual pos of cursor in row, not same as x pos due to tabs */ + 0, /* x pos of cursor in field */ + 0, /* y pos of cursor in field */ + 0, /* start of a new page on the form if 1 */ + 0, /* number of the page this field is on */ + A_NORMAL, /* character attributes for the foreground */ + A_NORMAL, /* character attributes for the background */ + ' ', /* padding character */ + DEFAULT_FORM_OPTS, /* options for the field */ + NULL, /* the form this field is bound to, if any */ + NULL, /* field above this one */ + NULL, /* field below this one */ + NULL, /* field to the left of this one */ + NULL, /* field to the right of this one */ + NULL, /* user defined pointer. */ + NULL, /* used if fields are linked */ + NULL, /* type struct for the field */ + {NULL, NULL}, /* circle queue glue for sorting fields */ + NULL, /* args for field type. */ + NULL, /* pointer to the array of lines structures. */ + NULL, /* list of lines available for reuse */ + NULL, /* array of buffers for the field */ +}; + +/* internal function prototypes */ +static int +field_buffer_init(FIELD *field, int buffer, unsigned int len); +static FIELD * +_formi_create_field(FIELD *, int, int, int, int, int, int); + + +/* + * Set the userptr for the field + */ +int +set_field_userptr(FIELD *field, void *ptr) +{ + FIELD *fp = (field == NULL) ? &_formi_default_field : field; + + fp->userptr = ptr; + + return E_OK; +} + +/* + * Return the userptr for the field. + */ + +void * +field_userptr(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.userptr; + else + return field->userptr; +} + +/* + * Set the options for the designated field. + */ +int +set_field_opts(FIELD *field, Form_Options options) +{ + int i; + + FIELD *fp = (field == NULL) ? &_formi_default_field : field; + + /* not allowed to set opts if the field is the current one */ + if ((field != NULL) && (field->parent != NULL) && + (field->parent->cur_field == field->index)) + return E_CURRENT; + + if ((options & O_STATIC) == O_STATIC) { + for (i = 0; i < fp->nbuf; i++) { + if (fp->buffers[i].length > fp->cols) + fp->buffers[i].string[fp->cols] = '\0'; + } + } + + fp->opts = options; + + /* if appropriate, redraw the field */ + if ((field != NULL) && (field->parent != NULL) + && (field->parent->posted == 1)) { + _formi_redraw_field(field->parent, field->index); + pos_form_cursor(field->parent); + wrefresh(field->parent->scrwin); + } + + return E_OK; +} + +/* + * Turn on the passed field options. + */ +int +field_opts_on(FIELD *field, Form_Options options) +{ + int i; + + FIELD *fp = (field == NULL) ? &_formi_default_field : field; + + /* not allowed to set opts if the field is the current one */ + if ((field != NULL) && (field->parent != NULL) && + (field->parent->cur_field == field->index)) + return E_CURRENT; + + if ((options & O_STATIC) == O_STATIC) { + for (i = 0; i < fp->nbuf; i++) { + if (fp->buffers[i].length > fp->cols) + fp->buffers[i].string[fp->cols] = '\0'; + } + } + + fp->opts |= options; + + /* if appropriate, redraw the field */ + if ((field != NULL) && (field->parent != NULL) + && (field->parent->posted == 1)) { + _formi_redraw_field(field->parent, field->index); + pos_form_cursor(field->parent); + wrefresh(field->parent->scrwin); + } + + return E_OK; +} + +/* + * Turn off the passed field options. + */ +int +field_opts_off(FIELD *field, Form_Options options) +{ + FIELD *fp = (field == NULL) ? &_formi_default_field : field; + + /* not allowed to set opts if the field is the current one */ + if ((field != NULL) && (field->parent != NULL) && + (field->parent->cur_field == field->index)) + return E_CURRENT; + + fp->opts &= ~options; + + /* if appropriate, redraw the field */ + if ((field != NULL) && (field->parent != NULL) + && (field->parent->posted == 1)) { + _formi_redraw_field(field->parent, field->index); + pos_form_cursor(field->parent); + wrefresh(field->parent->scrwin); + } + + return E_OK; +} + +/* + * Return the field options associated with the passed field. + */ +Form_Options +field_opts(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.opts; + else + return field->opts; +} + +/* + * Set the justification for the passed field. + */ +int +set_field_just(FIELD *field, int justification) +{ + FIELD *fp = (field == NULL) ? &_formi_default_field : field; + + /* + * not allowed to set justification if the field is + * the current one + */ + if ((field != NULL) && (field->parent != NULL) && + (field->parent->cur_field == field->index)) + return E_CURRENT; + + if ((justification < MIN_JUST_STYLE) /* check justification valid */ + || (justification > MAX_JUST_STYLE)) + return E_BAD_ARGUMENT; + + /* only allow justification on static, single row fields */ + if (((fp->opts & O_STATIC) != O_STATIC) || + ((fp->rows + fp->nrows) > 1)) + return E_BAD_ARGUMENT; + + fp->justification = justification; + + _formi_init_field_xpos(fp); + + return E_OK; +} + +/* + * Return the justification style of the field passed. + */ +int +field_just(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.justification; + else + return field->justification; +} + +/* + * Return information about the field passed. + */ +int +field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol, + int *nrow, int *nbuf) +{ + if (field == NULL) + return E_BAD_ARGUMENT; + + *rows = field->rows; + *cols = field->cols; + *frow = field->form_row; + *fcol = field->form_col; + *nrow = field->nrows; + *nbuf = field->nbuf; + + return E_OK; +} + +/* + * Report the dynamic field information. + */ +int +dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max) +{ + if (field == NULL) + return E_BAD_ARGUMENT; + + if ((field->opts & O_STATIC) == O_STATIC) { + *drows = field->rows; + *dcols = field->cols; + } else { + *drows = field->drows; + *dcols = field->dcols; + } + + *max = field->max; + + return E_OK; +} + +/* + * Init all the field variables, perform wrapping and other tasks + * after the field buffer is set. + */ +static int +field_buffer_init(FIELD *field, int buffer, unsigned int len) +{ + int status; + char *newp; + + if (buffer == 0) { + field->start_char = 0; + field->start_line = 0; + field->row_xpos = 0; + field->cursor_xpos = 0; + field->cursor_ypos = 0; + field->row_count = 1; /* must be at least one row XXX need to shift old rows (if any) to free list??? */ + field->alines->length = len; + if ((newp = realloc(field->alines->string, + (size_t) len + 1)) == NULL) + return E_SYSTEM_ERROR; + field->alines->string = newp; + field->alines->allocated = len + 1; + strlcpy(field->alines->string, field->buffers[buffer].string, + (size_t) len + 1); + field->alines->expanded = + _formi_tab_expanded_length(field->alines->string, + 0, field->alines->length); + + field->start_line = field->alines; + field->cur_line = field->alines; + + /* we have to hope the wrap works - if it does not then the + buffer is pretty much borked */ + status = _formi_wrap_field(field, field->cur_line); + if (status != E_OK) + return status; + + /* + * calculate the tabs for a single row field, the + * multiline case is handled when the wrap is done. + */ + if (field->row_count == 1) + _formi_calculate_tabs(field->alines); + + /* redraw the field to reflect the new contents. If the field + * is attached.... + */ + if ((field->parent != NULL) && (field->parent->posted == 1)) { + _formi_redraw_field(field->parent, field->index); + /* make sure cursor goes back to current field */ + pos_form_cursor(field->parent); + } + } + + return E_OK; +} + + +/* + * Set the field buffer to the string that results from processing + * the given format (fmt) using sprintf. + */ +int +set_field_printf(FIELD *field, int buffer, char *fmt, ...) +{ + int len; + va_list args; + + if (field == NULL) + return E_BAD_ARGUMENT; + + if (buffer >= field->nbuf) + return E_BAD_ARGUMENT; + + va_start(args, fmt); + /* check for buffer already existing, free the storage */ + if (field->buffers[buffer].allocated != 0) + free(field->buffers[buffer].string); + + len = vasprintf(&field->buffers[buffer].string, fmt, args); + va_end(args); + if (len < 0) + return E_SYSTEM_ERROR; + + field->buffers[buffer].length = len; + field->buffers[buffer].allocated = len + 1; + if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols) + && ((field->rows + field->nrows) == 1)) + len = field->cols; + + field->buffers[buffer].string[len] = '\0'; + return field_buffer_init(field, buffer, (unsigned int) len); +} + +/* + * Set the value of the field buffer to the value given. + */ + +int +set_field_buffer(FIELD *field, int buffer, char *value) +{ + unsigned int len; + int status; + + if (field == NULL) + return E_BAD_ARGUMENT; + + if (buffer >= field->nbuf) /* make sure buffer is valid */ + return E_BAD_ARGUMENT; + + len = (unsigned int) strlen(value); + if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols) + && ((field->rows + field->nrows) == 1)) + len = field->cols; + +#ifdef DEBUG + if (_formi_create_dbg_file() != E_OK) + return E_SYSTEM_ERROR; + + fprintf(dbg, + "set_field_buffer: entry: len = %d, value = %s, buffer=%d\n", + len, value, buffer); + fprintf(dbg, "set_field_buffer: entry: string = "); + if (field->buffers[buffer].string != NULL) + fprintf(dbg, "%s, len = %d\n", field->buffers[buffer].string, + field->buffers[buffer].length); + else + fprintf(dbg, "(null), len = 0\n"); + fprintf(dbg, "set_field_buffer: entry: lines.len = %d\n", + field->alines[0].length); +#endif + + if ((field->buffers[buffer].string = + (char *) realloc(field->buffers[buffer].string, + (size_t) len + 1)) == NULL) + return E_SYSTEM_ERROR; + + strlcpy(field->buffers[buffer].string, value, (size_t) len + 1); + field->buffers[buffer].length = len; + field->buffers[buffer].allocated = len + 1; + status = field_buffer_init(field, buffer, len); + +#ifdef DEBUG + fprintf(dbg, "set_field_buffer: exit: len = %d, value = %s\n", + len, value); + fprintf(dbg, "set_field_buffer: exit: string = %s, len = %d\n", + field->buffers[buffer].string, field->buffers[buffer].length); + fprintf(dbg, "set_field_buffer: exit: lines.len = %d\n", + field->alines[0].length); +#endif + + return status; +} + +/* + * Return the requested field buffer to the caller. + */ +char * +field_buffer(FIELD *field, int buffer) +{ + + char *reformat, *p; + _FORMI_FIELD_LINES *linep; + + if (field == NULL) + return NULL; + + if (buffer >= field->nbuf) + return NULL; + + /* + * We force a sync from the line structs to the buffer here. + * Traditional libform say we don't need to because it is + * done on a REQ_VALIDATE but NetBSD libform previously did + * not enforce this because the buffer contents were always + * current. Changes to line handling make this no longer so + * - the line structs may contain different data to the + * buffer if unsynced. + */ + if (_formi_sync_buffer(field) != E_OK) + return NULL; + + if ((field->opts & O_REFORMAT) != O_REFORMAT) { + return field->buffers[buffer].string; + } else { + if (field->row_count > 1) { + /* reformat */ + reformat = (char *) + malloc(strlen(field->buffers[buffer].string) + + ((field->row_count - 1) + * sizeof(char)) + 1); + + if (reformat == NULL) + return NULL; + + /* + * foreach row copy line, append newline, no + * newline on last row. + */ + p = reformat; + linep = field->alines; + + do + { + if (linep->length != 0) { + strncpy(p, linep->string, + (size_t) linep->length); + p += linep->length; + } + + linep = linep->next; + if (linep != NULL) + *p = '\n'; + p++; + } + while (linep != NULL); + + p = '\0'; + return reformat; + } else { + asprintf(&reformat, "%s", + field->buffers[buffer].string); + return reformat; + } + } +} + +/* + * Set the buffer 0 field status. + */ +int +set_field_status(FIELD *field, int status) +{ + + if (field == NULL) + return E_BAD_ARGUMENT; + + if (status != FALSE) + field->buf0_status = TRUE; + else + field->buf0_status = FALSE; + + return E_OK; +} + +/* + * Return the buffer 0 status flag for the given field. + */ +int +field_status(FIELD *field) +{ + + if (field == NULL) /* the default buffer 0 never changes :-) */ + return FALSE; + + return field->buf0_status; +} + +/* + * Set the maximum growth for a dynamic field. + */ +int +set_max_field(FIELD *fptr, int max) +{ + FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; + + if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */ + return E_BAD_ARGUMENT; + + if (max < 0) /* negative numbers are bad.... */ + return E_BAD_ARGUMENT; + + field->max = max; + return E_OK; +} + +/* + * Set the field foreground character attributes. + */ +int +set_field_fore(FIELD *fptr, chtype attribute) +{ + FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; + + field->fore = attribute; + return E_OK; +} + +/* + * Return the foreground character attribute for the given field. + */ +chtype +field_fore(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.fore; + else + return field->fore; +} + +/* + * Set the background character attribute for the given field. + */ +int +set_field_back(FIELD *field, chtype attribute) +{ + if (field == NULL) + _formi_default_field.back = attribute; + else + field->back = attribute; + + return E_OK; +} + +/* + * Get the background character attribute for the given field. + */ +chtype +field_back(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.back; + else + return field->back; +} + +/* + * Set the pad character for the given field. + */ +int +set_field_pad(FIELD *field, int pad) +{ + if (field == NULL) + _formi_default_field.pad = pad; + else + field->pad = pad; + + return E_OK; +} + +/* + * Return the padding character for the given field. + */ +int +field_pad(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.pad; + else + return field->pad; +} + +/* + * Set the field initialisation function hook. + */ +int +set_field_init(FORM *form, Form_Hook function) +{ + if (form == NULL) + _formi_default_form.field_init = function; + else + form->field_init = function; + + return E_OK; +} + +/* + * Return the function hook for the field initialisation. + */ +Form_Hook +field_init(FORM *form) +{ + if (form == NULL) + return _formi_default_form.field_init; + else + return form->field_init; +} + +/* + * Set the field termination function hook. + */ +int +set_field_term(FORM *form, Form_Hook function) +{ + if (form == NULL) + _formi_default_form.field_term = function; + else + form->field_term = function; + + return E_OK; +} + +/* + * Return the function hook defined for the field termination. + */ +Form_Hook +field_term(FORM *form) +{ + if (form == NULL) + return _formi_default_form.field_term; + else + return form->field_term; +} + +/* + * Set the page flag on the given field to indicate it is the start of a + * new page. + */ +int +set_new_page(FIELD *fptr, int page) +{ + FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; + + if (field->parent != NULL) /* check if field is connected to a form */ + return E_CONNECTED; + + field->page_break = (page != FALSE); + return E_OK; +} + +/* + * Return the page status for the given field. TRUE is returned if the + * field is the start of a new page. + */ +int +new_page(FIELD *field) +{ + if (field == NULL) + return _formi_default_field.page_break; + else + return field->page_break; +} + +/* + * Return the index of the field in the form fields array. + */ +int +field_index(FIELD *field) +{ + if (field == NULL) + return E_BAD_ARGUMENT; + + if (field->parent == NULL) + return E_NOT_CONNECTED; + + return field->index; +} + +/* + * Internal function that does most of the work to create a new field. + * The new field is initialised from the information in the prototype + * field passed. + * Returns NULL on error. + */ +static FIELD * +_formi_create_field(FIELD *prototype, int rows, int cols, int frow, + int fcol, int nrows, int nbuf) +{ + FIELD *new; + + if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) || + (nrows < 0) || (nbuf < 0)) + return NULL; + + if ((new = (FIELD *)malloc(sizeof(FIELD))) == NULL) { + return NULL; + } + + /* copy in the default field info */ + bcopy(prototype, new, sizeof(FIELD)); + + new->nbuf = nbuf + 1; + new->rows = rows; + new->cols = cols; + new->form_row = frow; + new->form_col = fcol; + new->nrows = nrows; + new->link = new; + return new; +} + +/* + * Create a new field structure. + */ +FIELD * +new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf) +{ + FIELD *new; + size_t buf_len; + int i; + + + if ((new = _formi_create_field(&_formi_default_field, rows, cols, + frow, fcol, nrows, nbuf)) == NULL) + return NULL; + + buf_len = (nbuf + 1) * sizeof(FORM_STR); + + if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { + free(new); + return NULL; + } + + /* Initialise the strings to a zero length string */ + for (i = 0; i < nbuf + 1; i++) { + if ((new->buffers[i].string = + (char *) malloc(sizeof(char))) == NULL) { + free(new->buffers); + free(new); + return NULL; + } + new->buffers[i].string[0] = '\0'; + new->buffers[i].length = 0; + new->buffers[i].allocated = 1; + } + + if ((new->alines = (_FORMI_FIELD_LINES *) + malloc(sizeof(struct _formi_field_lines))) == NULL) { + free(new->buffers); + free(new); + return NULL; + } + + new->alines->prev = NULL; + new->alines->next = NULL; + new->alines->allocated = 0; + new->alines->length = 0; + new->alines->expanded = 0; + new->alines->string = NULL; + new->alines->hard_ret = FALSE; + new->alines->tabs = NULL; + new->start_line = new->alines; + new->cur_line = new->alines; + + return new; +} + +/* + * Duplicate the given field, including it's buffers. + */ +FIELD * +dup_field(FIELD *field, int frow, int fcol) +{ + FIELD *new; + size_t row_len, buf_len; + + if (field == NULL) + return NULL; + + /* XXXX this right???? */ + if ((new = _formi_create_field(field, (int) field->rows, + (int ) field->cols, + frow, fcol, (int) field->nrows, + field->nbuf - 1)) == NULL) + return NULL; + + row_len = (field->rows + field->nrows + 1) * field->cols; + buf_len = (field->nbuf + 1) * row_len * sizeof(FORM_STR); + + if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { + free(new); + return NULL; + } + + /* copy the buffers from the source field into the new copy */ + bcopy(field->buffers, new->buffers, buf_len); + + return new; +} + +/* + * Create a new field at the specified location by duplicating the given + * field. The buffers are shared with the parent field. + */ +FIELD * +link_field(FIELD *field, int frow, int fcol) +{ + FIELD *new; + + if (field == NULL) + return NULL; + + if ((new = _formi_create_field(field, (int) field->rows, + (int) field->cols, + frow, fcol, (int) field->nrows, + field->nbuf - 1)) == NULL) + return NULL; + + new->link = field->link; + field->link = new; + + /* we are done. The buffer pointer was copied during the field + creation. */ + return new; +} + +/* + * Release all storage allocated to the field + */ +int +free_field(FIELD *field) +{ + FIELD *flink; + int i; + _formi_tab_t *ts, *nts; + + if (field == NULL) + return E_BAD_ARGUMENT; + + if (field->parent != NULL) + return E_CONNECTED; + + if (field->link == field) { /* check if field linked */ + /* no it is not - release the buffers */ + free(field->buffers); + /* free the tab structures */ + for (i = 0; i < field->row_count - 1; i++) { + if (field->alines[i].tabs != NULL) { + ts = field->alines[i].tabs; + while (ts != NULL) { + nts = ts->fwd; + free(ts); + ts = nts; + } + } + } + } else { + /* is linked, traverse the links to find the field referring + * to the one to be freed. + */ + for (flink = field->link; flink != field; flink = flink->link); + flink->link = field->link; + } + + free(field); + return E_OK; +} + + diff --git a/lib/libform/field_types.c b/lib/libform/field_types.c new file mode 100644 index 000000000..db7e59ae0 --- /dev/null +++ b/lib/libform/field_types.c @@ -0,0 +1,274 @@ +/* $NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: field_types.c,v 1.7 2006/03/19 20:02:27 christos Exp $"); + +#include +#include +#include "form.h" +#include "internals.h" + +extern FIELD _formi_default_field; + +/* function prototypes.... */ +static void +_formi_create_field_args(FIELDTYPE *type, char **type_args, + formi_type_link **link, va_list *args, int *error); +static FIELDTYPE * +_formi_create_fieldtype(void); + +/* + * Process the arguments, if any, for the field type. + */ +static void +_formi_create_field_args(FIELDTYPE *type, char **type_args, + formi_type_link **link, va_list *args, int *error) +{ + formi_type_link *l; + + l = NULL; + if ((type != NULL) + && ((type->flags & _TYPE_HAS_ARGS) == _TYPE_HAS_ARGS)) { + if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) { + l = malloc(sizeof(*l)); + if (l != NULL) { + _formi_create_field_args(type->link->next, + type_args, + &type->link->next->link, + args, + error); + _formi_create_field_args(type->link->prev, + type_args, + &type->link->prev->link, + args, + error); + (*link) = l; + } + + (*error)++; + } else { + if ((*type_args = (char *) type->make_args(args)) + == NULL) + (*error)++; + } + } +} + +/* + * Allocate a new fieldtype structure, initialise it and return the + * struct to the caller. + */ +static FIELDTYPE * +_formi_create_fieldtype(void) +{ + FIELDTYPE *new; + + if ((new = malloc(sizeof(*new))) == NULL) + return NULL; + + new->flags = _TYPE_NO_FLAGS; + new->refcount = 0; + new->link = NULL; + new->make_args = NULL; + new->copy_args = NULL; + new->free_args = NULL; + new->field_check = NULL; + new->char_check = NULL; + new->next_choice = NULL; + new->prev_choice = NULL; + + return new; +} + +/* + * Set the field type of the field to be the one given. + */ +int +set_field_type(FIELD *fptr, FIELDTYPE *type, ...) +{ + va_list args; + FIELD *field; + int error = 0; + + va_start(args, type); + + field = (fptr == NULL)? &_formi_default_field : fptr; + + field->type = type; + _formi_create_field_args(type, &field->args, &type->link, &args, + &error); + va_end(args); + + if (error) + return E_BAD_ARGUMENT; + + return E_OK; +} + +/* + * Return the field type associated with the given field + */ +FIELDTYPE * +field_type(FIELD *fptr) +{ + FIELD *field; + + field = (fptr == NULL)? &_formi_default_field : fptr; + + return field->type; +} + + +/* + * Return the field arguments for the given field. + */ +char * +field_arg(FIELD *fptr) +{ + FIELD *field; + + field = (fptr == NULL)? &_formi_default_field : fptr; + + return field->args; +} + +/* + * Create a new field type. Caller must specify a field_check routine + * and char_check routine. + */ +FIELDTYPE * +new_fieldtype(int (*field_check)(FIELD *, char *), + int (*char_check)(int, char *)) +{ + FIELDTYPE *new; + + if ((field_check == NULL) && (char_check == NULL)) + return NULL; + + if ((new = _formi_create_fieldtype()) != NULL) { + new->field_check = field_check; + new->char_check = char_check; + } + + return new; +} + +/* + * Free the storage used by the fieldtype. + */ +int +free_fieldtype(FIELDTYPE *fieldtype) +{ + if (fieldtype == NULL) + return E_BAD_ARGUMENT; + + if (fieldtype->refcount > 0) + return E_CONNECTED; + + if ((fieldtype->flags & _TYPE_IS_BUILTIN) == _TYPE_IS_BUILTIN) + return E_BAD_ARGUMENT; /* don't delete builtin types! */ + + if ((fieldtype->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) + { + fieldtype->link->next->refcount--; + fieldtype->link->prev->refcount--; + } + + free(fieldtype); + + return E_OK; +} + +/* + * Set the field type arguments for the given field type. + */ +int +set_fieldtype_arg(FIELDTYPE *fieldtype, char * (*make_args)(va_list *), + char * (*copy_args)(char*), void (*free_args)(char *)) +{ + if ((fieldtype == NULL) || (make_args == NULL) + || (copy_args == NULL) || (free_args == NULL)) + return E_BAD_ARGUMENT; + + fieldtype->make_args = make_args; + fieldtype->copy_args = copy_args; + fieldtype->free_args = free_args; + + return E_OK; +} + +/* + * Set up the choice list functions for the given fieldtype. + */ +int +set_fieldtype_choice(FIELDTYPE *fieldtype, int (*next_choice)(FIELD *, char *), + int (*prev_choice)(FIELD *, char *)) +{ + if ((fieldtype == NULL) || (next_choice == NULL) + || (prev_choice == NULL)) + return E_BAD_ARGUMENT; + + fieldtype->next_choice = next_choice; + fieldtype->prev_choice = prev_choice; + + return E_OK; +} + +/* + * Link the two given types to produce a new type, return this new type. + */ +FIELDTYPE * +link_fieldtype(FIELDTYPE *type1, FIELDTYPE *type2) +{ + FIELDTYPE *new; + + if ((type1 == NULL) || (type2 == NULL)) + return NULL; + + if ((new = _formi_create_fieldtype()) == NULL) + return NULL; + + new->flags = _TYPE_IS_LINKED; + new->flags |= ((type1->flags & _TYPE_HAS_ARGS) + | (type2->flags & _TYPE_HAS_ARGS)); + if ((new->link = malloc(sizeof(*new->link))) == NULL) { + free(new); + return NULL; + } + + new->link->prev = type1; + new->link->next = type2; + type1->refcount++; + type2->refcount++; + + return new; +} diff --git a/lib/libform/form.c b/lib/libform/form.c new file mode 100644 index 000000000..7be3d3c8b --- /dev/null +++ b/lib/libform/form.c @@ -0,0 +1,613 @@ +/* $NetBSD: form.c,v 1.15 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: form.c,v 1.15 2004/11/24 11:57:09 blymn Exp $"); + +#include +#include +#include +#include "internals.h" + +extern FIELD _formi_default_field; + +FORM _formi_default_form = { + FALSE, /* true if performing a init or term function */ + FALSE, /* the form is posted */ + FALSE, /* make field list circular if true */ + NULL, /* window for the form */ + NULL, /* subwindow for the form */ + NULL, /* use this window for output */ + NULL, /* user defined pointer */ + 0, /* options for the form */ + NULL, /* function called when form posted and + after page change */ + NULL, /* function called when form is unposted and + before page change */ + NULL, /* function called when form posted and after + current field changes */ + NULL, /* function called when form unposted and + before current field changes */ + 0, /* number of fields attached */ + 0, /* current field */ + 0, /* current page of form */ + 0, /* number of pages in the form */ + NULL, /* dynamic array of fields that start + the pages */ + {NULL, NULL}, /* sorted field list */ + NULL /* array of fields attached to this form. */ +}; + +/* + * Set the window associated with the form + */ +int +set_form_win(FORM *form, WINDOW *win) +{ + if (form == NULL) { + _formi_default_form.win = win; + _formi_default_form.scrwin = win; + } else { + if (form->posted == TRUE) + return E_POSTED; + else { + form->win = win; + form->scrwin = win; + } + } + + return E_OK; +} + +/* + * Return the window used by the given form + */ +WINDOW * +form_win(FORM *form) +{ + if (form == NULL) + return _formi_default_form.win; + else + return form->win; +} + +/* + * Set the subwindow for the form. + */ +int +set_form_sub(FORM *form, WINDOW *window) +{ + if (form == NULL) { + _formi_default_form.subwin = window; + _formi_default_form.scrwin = window; + } else { + if (form->posted == TRUE) + return E_POSTED; + else { + form->subwin = window; + form->scrwin = window; + } + } + + return E_OK; +} + +/* + * Return the subwindow for the given form. + */ +WINDOW * +form_sub(FORM *form) +{ + if (form == NULL) + return _formi_default_form.subwin; + else + return form->subwin; +} + +/* + * Return the minimum size required to contain the form. + */ +int +scale_form(FORM *form, int *rows, int *cols) +{ + int i, max_row, max_col, temp; + + if ((form->fields == NULL) || (form->fields[0] == NULL)) + return E_NOT_CONNECTED; + + max_row = 0; + max_col = 0; + + for (i = 0; i < form->field_count; i++) { + temp = form->fields[i]->form_row + form->fields[i]->rows; + max_row = (temp > max_row)? temp : max_row; + temp = form->fields[i]->form_col + form->fields[i]->cols; + max_col = (temp > max_col)? temp : max_col; + } + + (*rows) = max_row; + (*cols) = max_col; + + return E_OK; +} + +/* + * Set the user defined pointer for the form given. + */ +int +set_form_userptr(FORM *form, void *ptr) +{ + if (form == NULL) + _formi_default_form.userptr = ptr; + else + form->userptr = ptr; + + return E_OK; +} + +/* + * Return the user defined pointer associated with the given form. + */ +void * +form_userptr(FORM *form) +{ + + if (form == NULL) + return _formi_default_form.userptr; + else + return form->userptr; +} + +/* + * Set the form options to the given ones. + */ +int +set_form_opts(FORM *form, Form_Options options) +{ + if (form == NULL) + _formi_default_form.opts = options; + else + form->opts = options; + + return E_OK; +} + +/* + * Turn the given options on for the form. + */ +int +form_opts_on(FORM *form, Form_Options options) +{ + if (form == NULL) + _formi_default_form.opts |= options; + else + form->opts |= options; + + return E_OK; +} + +/* + * Turn the given options off for the form. + */ +int +form_opts_off(FORM *form, Form_Options options) +{ + if (form == NULL) + _formi_default_form.opts &= ~options; + else + form->opts &= ~options; + + + return E_OK; +} + +/* + * Return the options set for the given form. + */ +Form_Options +form_opts(FORM *form) +{ + if (form == NULL) + return _formi_default_form.opts; + else + return form->opts; +} + +/* + * Set the form init function for the given form + */ +int +set_form_init(FORM *form, Form_Hook func) +{ + if (form == NULL) + _formi_default_form.form_init = func; + else + form->form_init = func; + + return E_OK; +} + +/* + * Return the init function associated with the given form. + */ +Form_Hook +form_init(FORM *form) +{ + if (form == NULL) + return _formi_default_form.form_init; + else + return form->form_init; +} + +/* + * Set the function to be called on form termination. + */ +int +set_form_term(FORM *form, Form_Hook function) +{ + if (form == NULL) + _formi_default_form.form_term = function; + else + form->form_term = function; + + return E_OK; +} + +/* + * Return the function defined for the termination function. + */ +Form_Hook +form_term(FORM *form) +{ + + if (form == NULL) + return _formi_default_form.form_term; + else + return form->form_term; +} + + +/* + * Attach the given fields to the form. + */ +int +set_form_fields(FORM *form, FIELD **fields) +{ + int num_fields = 0, i, maxpg = 1, status; + + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->posted == TRUE) + return E_POSTED; + + if (fields == NULL) + return E_BAD_ARGUMENT; + + while (fields[num_fields] != NULL) { + if ((fields[num_fields]->parent != NULL) && + (fields[num_fields]->parent != form)) + return E_CONNECTED; + num_fields++; + } + + /* disconnect old fields, if any */ + if (form->fields != NULL) { + for (i = 0; i < form->field_count; i++) { + form->fields[i]->parent = NULL; + form->fields[i]->index = -1; + } + } + + /* kill old page pointers if any */ + if (form->page_starts != NULL) + free(form->page_starts); + + form->field_count = num_fields; + + /* now connect the new fields to the form */ + for (i = 0; i < num_fields; i++) { + fields[i]->parent = form; + fields[i]->index = i; + /* set the page number of the field */ + if (fields[i]->page_break == 1) + maxpg++; + fields[i]->page = maxpg; + } + + form->fields = fields; + form->cur_field = 0; + form->max_page = maxpg; + if ((status = _formi_find_pages(form)) != E_OK) + return status; + + /* sort the fields and set the navigation pointers */ + _formi_sort_fields(form); + _formi_stitch_fields(form); + + return E_OK; +} + +/* + * Return the fields attached to the form given. + */ +FIELD ** +form_fields(FORM *form) +{ + if (form == NULL) + return NULL; + + return form->fields; +} + +/* + * Return the number of fields attached to the given form. + */ +int +field_count(FORM *form) +{ + if (form == NULL) + return -1; + + return form->field_count; +} + +/* + * Move the given field to the row and column given. + */ +int +move_field(FIELD *fptr, int frow, int fcol) +{ + FIELD *field = (fptr == NULL) ? &_formi_default_field : fptr; + + if (field->parent != NULL) + return E_CONNECTED; + + field->form_row = frow; + field->form_col = fcol; + + return E_OK; +} + +/* + * Set the page of the form to the given page. + */ +int +set_form_page(FORM *form, int page) +{ + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->in_init == TRUE) + return E_BAD_STATE; + + if (page > form->max_page) + return E_BAD_ARGUMENT; + + form->page = page; + return E_OK; +} + +/* + * Return the maximum page of the form. + */ +int +form_max_page(FORM *form) +{ + if (form == NULL) + return _formi_default_form.max_page; + else + return form->max_page; +} + +/* + * Return the current page of the form. + */ +int +form_page(FORM *form) +{ + if (form == NULL) + return E_BAD_ARGUMENT; + + return form->page; +} + +/* + * Set the current field to the field given. + */ +int +set_current_field(FORM *form, FIELD *field) +{ + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->in_init == TRUE) + return E_BAD_STATE; + + if (field == NULL) + return E_INVALID_FIELD; + + if ((field->parent == NULL) || (field->parent != form)) + return E_INVALID_FIELD; /* field is not of this form */ + + form->cur_field = field->index; + + /* XXX update page if posted??? */ + return E_OK; +} + +/* + * Return the current field of the given form. + */ +FIELD * +current_field(FORM *form) +{ + if (form == NULL) + return NULL; + + if (form->fields == NULL) + return NULL; + + return form->fields[form->cur_field]; +} + +/* + * Allocate a new form with the given fields. + */ +FORM * +new_form(FIELD **fields) +{ + FORM *new; + + if ((new = (FORM *) malloc(sizeof(FORM))) == NULL) + return NULL; + + + /* copy in the defaults... */ + bcopy(&_formi_default_form, new, sizeof(FORM)); + + if (new->win == NULL) + new->scrwin = stdscr; /* something for curses to write to */ + + if (fields != NULL) { /* attach the fields, if any */ + if (set_form_fields(new, fields) < 0) { + free(new); /* field attach failed, back out */ + return NULL; + } + } + + return new; +} + +/* + * Free the given form. + */ +int +free_form(FORM *form) +{ + int i; + + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->posted == TRUE) + return E_POSTED; + + for (i = 0; i < form->field_count; i++) { + /* detach all the fields from the form */ + form->fields[i]->parent = NULL; + form->fields[i]->index = -1; + } + + free(form); + + return E_OK; +} + +/* + * Tell if the current field of the form has offscreen data ahead + */ +int +data_ahead(FORM *form) +{ + FIELD *cur; + + if ((form == NULL) || (form->fields == NULL) + || (form->fields[0] == NULL)) + return FALSE; + + cur = form->fields[form->cur_field]; + + /*XXXX wrong */ + if (cur->cur_line->expanded > cur->cols) + return TRUE; + + return FALSE; +} + +/* + * Tell if current field of the form has offscreen data behind + */ +int +data_behind(FORM *form) +{ + FIELD *cur; + + if ((form == NULL) || (form->fields == NULL) + || (form->fields[0] == NULL)) + return FALSE; + + cur = form->fields[form->cur_field]; + + if (cur->start_char > 0) + return TRUE; + + return FALSE; +} + +/* + * Position the form cursor. + */ +int +pos_form_cursor(FORM *form) +{ + FIELD *cur; + int row, col; + + if ((form == NULL) || (form->fields == NULL) || + (form->fields[0] == NULL)) + return E_BAD_ARGUMENT; + + if (form->posted != 1) + return E_NOT_POSTED; + + cur = form->fields[form->cur_field]; + row = cur->form_row; + col = cur->form_col; + + /* if the field is public then show the cursor pos */ + if ((cur->opts & O_PUBLIC) == O_PUBLIC) { + row += cur->cursor_ypos; + col += cur->cursor_xpos; + if (cur->cursor_xpos >= cur->cols) { + col = cur->form_col; + row++; + } + } + +#ifdef DEBUG + fprintf(dbg, "pos_cursor: row=%d, col=%d\n", row, col); +#endif + + wmove(form->scrwin, row, col); + + return E_OK; +} diff --git a/lib/libform/form.h b/lib/libform/form.h new file mode 100644 index 000000000..f62095012 --- /dev/null +++ b/lib/libform/form.h @@ -0,0 +1,382 @@ +/* $NetBSD: form.h,v 1.21 2011/11/28 12:44:18 joerg Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#ifndef FORM_H +#define FORM_H 1 +#include +#include +#include +#include + +/* Define the types of field justification that can be used. */ +#define NO_JUSTIFICATION (0) +#define JUSTIFY_RIGHT (1) +#define JUSTIFY_LEFT (2) +#define JUSTIFY_CENTER (3) + +/* Define the max and min valid justification styles for range checking */ +#define MIN_JUST_STYLE NO_JUSTIFICATION +#define MAX_JUST_STYLE JUSTIFY_CENTER + +/* Options for the fields */ +typedef unsigned int Form_Options; + +/* form options */ +#define O_BS_OVERLOAD (0x001) +#define O_NL_OVERLOAD (0x002) + +/* field options */ +#define O_VISIBLE (0x001) /* Field is visible */ +#define O_ACTIVE (0x002) /* Field is active in the form */ +#define O_PUBLIC (0x004) /* The contents entered into the field is echoed */ +#define O_EDIT (0x008) /* Can edit the field */ +#define O_WRAP (0x010) /* The field contents can line wrap */ +#define O_BLANK (0x020) /* Blank the field on modification */ +#define O_AUTOSKIP (0x040) /* Skip to next field when current is full */ +#define O_NULLOK (0x080) /* Field is allowed to contain no data */ +#define O_STATIC (0x100) /* Field is not dynamic */ +#define O_PASSOK (0x200) /* An umodified field is OK */ +#define O_REFORMAT (0x400) /* Insert newlines at linebreaks on buffer get */ + +/* + * Form driver requests - be VERY careful about changing the ordering + * of the requests below. The form driver code depends on a particular + * order for the requests. + */ +#define REQ_MIN_REQUEST (KEY_MAX + 0x101) /* must equal value of the + first request */ + +#define REQ_NEXT_PAGE (KEY_MAX + 0x101) /* next page in form */ +#define REQ_PREV_PAGE (KEY_MAX + 0x102) /* previous page in form */ +#define REQ_FIRST_PAGE (KEY_MAX + 0x103) /* goto first page in form */ +#define REQ_LAST_PAGE (KEY_MAX + 0x104) /* goto last page in form */ + +#define REQ_NEXT_FIELD (KEY_MAX + 0x105) /* move to the next field */ +#define REQ_PREV_FIELD (KEY_MAX + 0x106) /* move to the previous field */ +#define REQ_FIRST_FIELD (KEY_MAX + 0x107) /* goto the first field */ +#define REQ_LAST_FIELD (KEY_MAX + 0x108) /* goto the last field */ + +#define REQ_SNEXT_FIELD (KEY_MAX + 0x109) /* move to the next field + in sorted order */ +#define REQ_SPREV_FIELD (KEY_MAX + 0x10a) /* move to the prev field + in sorted order */ +#define REQ_SFIRST_FIELD (KEY_MAX + 0x10b) /* move to the first + sorted field */ +#define REQ_SLAST_FIELD (KEY_MAX + 0x10c) /* move to the last sorted + field */ + +#define REQ_LEFT_FIELD (KEY_MAX + 0x10d) /* go left one field */ +#define REQ_RIGHT_FIELD (KEY_MAX + 0x10e) /* go right one field */ +#define REQ_UP_FIELD (KEY_MAX + 0x10f) /* go up one field */ +#define REQ_DOWN_FIELD (KEY_MAX + 0x110) /* go down one field */ + +#define REQ_NEXT_CHAR (KEY_MAX + 0x111) /* move to the next char + in field */ +#define REQ_PREV_CHAR (KEY_MAX + 0x112) /* move to the previous + char in field */ +#define REQ_NEXT_LINE (KEY_MAX + 0x113) /* go to the next line in + the field */ +#define REQ_PREV_LINE (KEY_MAX + 0x114) /* go to the previous line + in the field */ +#define REQ_NEXT_WORD (KEY_MAX + 0x115) /* go to the next word in + the field */ +#define REQ_PREV_WORD (KEY_MAX + 0x116) /* go to the previous word + in the field */ +#define REQ_BEG_FIELD (KEY_MAX + 0x117) /* go to the beginning of + the field */ +#define REQ_END_FIELD (KEY_MAX + 0x118) /* go to the end of the field */ +#define REQ_BEG_LINE (KEY_MAX + 0x119) /* go to the beginning of + the line */ +#define REQ_END_LINE (KEY_MAX + 0x11a) /* go to the end of the + line */ +#define REQ_LEFT_CHAR (KEY_MAX + 0x11b) /* move left in the field */ +#define REQ_RIGHT_CHAR (KEY_MAX + 0x11c) /* move right in the field */ +#define REQ_UP_CHAR (KEY_MAX + 0x11d) /* move up in the field */ +#define REQ_DOWN_CHAR (KEY_MAX + 0x11e) /* move down in the field */ + +#define REQ_NEW_LINE (KEY_MAX + 0x11f) /* insert/overlay a new line */ +#define REQ_INS_CHAR (KEY_MAX + 0x120) /* insert a blank char at + the cursor */ +#define REQ_INS_LINE (KEY_MAX + 0x121) /* insert a blank line at + the cursor */ + +#define REQ_DEL_CHAR (KEY_MAX + 0x122) /* delete the current character */ +#define REQ_DEL_PREV (KEY_MAX + 0x123) /* delete the character + before the current */ +#define REQ_DEL_LINE (KEY_MAX + 0x124) /* delete the current line */ +#define REQ_DEL_WORD (KEY_MAX + 0x125) /* delete the word at the cursor */ +#define REQ_CLR_EOL (KEY_MAX + 0x126) /* clear to the end of the line */ +#define REQ_CLR_EOF (KEY_MAX + 0x127) /* clear to the end of the field */ +#define REQ_CLR_FIELD (KEY_MAX + 0x128) /* clear the field */ + +#define REQ_OVL_MODE (KEY_MAX + 0x129) /* overlay mode */ +#define REQ_INS_MODE (KEY_MAX + 0x12a) /* insert mode */ + +#define REQ_SCR_FLINE (KEY_MAX + 0x12b) /* scroll field forward one line */ +#define REQ_SCR_BLINE (KEY_MAX + 0x12c) /* scroll field backward + one line */ +#define REQ_SCR_FPAGE (KEY_MAX + 0x12d) /* scroll field forward one page */ +#define REQ_SCR_BPAGE (KEY_MAX + 0x12e) /* scroll field backward + one page */ +#define REQ_SCR_FHPAGE (KEY_MAX + 0x12f) /* scroll field forward + half a page */ +#define REQ_SCR_BHPAGE (KEY_MAX + 0x130) /* scroll field backward + half a page */ + +#define REQ_SCR_FCHAR (KEY_MAX + 0x131) /* horizontal scroll + forward a character */ +#define REQ_SCR_BCHAR (KEY_MAX + 0x132) /* horizontal scroll + backward a character */ +#define REQ_SCR_HFLINE (KEY_MAX + 0x133) /* horizontal scroll + forward a line */ +#define REQ_SCR_HBLINE (KEY_MAX + 0x134) /* horizontal scroll + backward a line */ +#define REQ_SCR_HFHALF (KEY_MAX + 0x135) /* horizontal scroll + forward half a line */ +#define REQ_SCR_HBHALF (KEY_MAX + 0x136) /* horizontal scroll + backward half a line */ + +#define REQ_VALIDATION (KEY_MAX + 0x137) /* validate the field */ +#define REQ_PREV_CHOICE (KEY_MAX + 0x138) /* display previous field choice */ +#define REQ_NEXT_CHOICE (KEY_MAX + 0x139) /* display next field choice */ + +#define REQ_MAX_COMMAND (KEY_MAX + 0x139) /* must match the last + driver command */ + +/* The following defines are for ncurses compatibility */ +#define MIN_FORM_COMMAND REQ_MIN_REQUEST +#define MAX_FORM_COMMAND REQ_MAX_COMMAND + + +typedef struct _form_string { + size_t allocated; + unsigned int length; + char *string; +} FORM_STR; + +typedef struct _form_field FIELD; +typedef struct _form_struct FORM; +typedef struct _form_fieldtype FIELDTYPE; + +typedef struct _formi_page_struct _FORMI_PAGE_START; +typedef struct formi_type_link_struct _FORMI_TYPE_LINK; +typedef struct _formi_field_lines _FORMI_FIELD_LINES; + + +typedef void (*Form_Hook)(FORM *); + +/* definition of a field in the form */ +struct _form_field { + unsigned int rows; /* rows in the field */ + unsigned int cols; /* columns in the field */ + unsigned int drows; /* dynamic rows */ + unsigned int dcols; /* dynamic columns */ + unsigned int max; /* maximum growth */ + unsigned int form_row; /* starting row in the form subwindow */ + unsigned int form_col; /* starting column in the form subwindow */ + unsigned int nrows; /* number of off screen rows */ + int index; /* index of this field in form fields array. */ + int nbuf; /* number of buffers associated with this field */ + int buf0_status; /* set to true if buffer 0 has changed. */ + int justification; /* justification style of the field */ + int overlay; /* set to true if field is in overlay mode */ + _FORMI_FIELD_LINES *cur_line; /* pointer to the current line cursor + is on */ + unsigned int start_char; /* starting char in string (horiz scroll) */ + _FORMI_FIELD_LINES *start_line; /* start line in field (vert scroll) */ + unsigned int row_count; /* number of rows actually used in field */ + unsigned int row_xpos; /* char offset of cursor in field, not same + as cursor_xpos due to tab expansion */ + unsigned int cursor_xpos; /* x pos of cursor in field */ + unsigned int cursor_ypos; /* y pos of cursor in field */ + short page_break; /* start of a new page on the form if 1 */ + short page; /* number of the page this field is on */ + chtype fore; /* character attributes for the foreground */ + chtype back; /* character attributes for the background */ + int pad; /* padding character */ + Form_Options opts; /* options for the field */ + FORM *parent; /* the form this field is bound to, if any */ + FIELD *up; /* field above this one */ + FIELD *down; /* field below this one */ + FIELD *left; /* field to the left of this one */ + FIELD *right; /* field to the right of this one */ + void *userptr; /* user defined pointer. */ + FIELD *link; /* used if fields are linked */ + FIELDTYPE *type; /* type struct for the field */ + CIRCLEQ_ENTRY(_form_field) glue; /* circle queue glue for sorting fields */ + char *args; /* args for field type. */ + _FORMI_FIELD_LINES *alines; /* array of the starts and ends of lines */ + _FORMI_FIELD_LINES *free; /* list of lines available for reuse */ + FORM_STR *buffers; /* array of buffers for the field */ +}; + +/* define the types of fields we can have */ +extern FIELDTYPE *TYPE_ALNUM; +extern FIELDTYPE *TYPE_ALPHA; +extern FIELDTYPE *TYPE_ENUM; +extern FIELDTYPE *TYPE_INTEGER; +extern FIELDTYPE *TYPE_NUMERIC; +extern FIELDTYPE *TYPE_REGEXP; +extern FIELDTYPE *TYPE_IPV4; +extern FIELDTYPE *TYPE_IPV6; +extern FIELDTYPE *TYPE_USER; + +/* definition of a field type. */ +struct _form_fieldtype { + unsigned flags; /* status of the type */ + unsigned refcount; /* in use if > 0 */ + _FORMI_TYPE_LINK *link; /* set if this type is linked */ + + char * (*make_args)(va_list *); /* make the args for the type */ + char * (*copy_args)(char *); /* copy the args for the type */ + void (*free_args)(char *); /* free storage used by the args */ + int (*field_check)(FIELD *, char *); /* field validation routine */ + int (*char_check)(int, char *); /* char validation routine */ + int (*next_choice)(FIELD *, char *); /* function to select next + choice */ + int (*prev_choice)(FIELD *, char *); /* function to select prev + choice */ +}; + +/*definition of a form */ + +struct _form_struct { + int in_init; /* true if performing a init or term function */ + int posted; /* the form is posted */ + int wrap; /* wrap from last field to first field if true */ + WINDOW *win; /* window for the form */ + WINDOW *subwin; /* subwindow for the form */ + WINDOW *scrwin; /* this is the window to use for output */ + void *userptr; /* user defined pointer */ + Form_Options opts; /* options for the form */ + Form_Hook form_init; /* function called when form posted and + after page change */ + Form_Hook form_term; /* function called when form is unposted and + before page change */ + Form_Hook field_init; /* function called when form posted and after + current field changes */ + Form_Hook field_term; /* function called when form unposted and + before current field changes */ + int field_count; /* number of fields attached */ + int cur_field; /* current field */ + int page; /* current page of form */ + int max_page; /* number of pages in the form */ + _FORMI_PAGE_START *page_starts; /* dynamic array of fields that start + the pages */ + CIRCLEQ_HEAD(_formi_sort_head, _form_field) sorted_fields; /* sorted field + list */ + FIELD **fields; /* array of fields attached to this form. */ +}; + +/* Public function prototypes. */ +__BEGIN_DECLS + +FIELD *current_field(FORM *); +int data_ahead(FORM *); +int data_behind(FORM *); +FIELD *dup_field(FIELD *, int, int); +int dynamic_field_info(FIELD *, int *, int *, int *); +char *field_arg(FIELD *); +chtype field_back(FIELD *); +char *field_buffer(FIELD *, int); +int field_count(FORM *); +chtype field_fore(FIELD *); +int field_index(FIELD *); +int field_info(FIELD *, int *, int *, int *, int *, int *, int *); +Form_Hook field_init(FORM *); +int field_just(FIELD *); +Form_Options field_opts(FIELD *); +int field_opts_off(FIELD *, Form_Options); +int field_opts_on(FIELD *, Form_Options); +int field_pad(FIELD *); +int field_status(FIELD *); +Form_Hook field_term(FORM *); +FIELDTYPE *field_type(FIELD *); +void *field_userptr(FIELD *); +int form_driver(FORM *, int); +FIELD **form_fields(FORM *); +Form_Hook form_init(FORM *); +int form_max_page(FORM *); +Form_Options form_opts(FORM *); +int form_opts_off(FORM *, Form_Options); +int form_opts_on(FORM *, Form_Options); +int form_page(FORM *); +WINDOW *form_sub(FORM *); +Form_Hook form_term(FORM *); +void *form_userptr(FORM *); +WINDOW *form_win(FORM *); +int free_field(FIELD *); +int free_fieldtype(FIELDTYPE *); +int free_form(FORM *); +FIELD *link_field(FIELD *, int, int); +FIELDTYPE *link_fieldtype(FIELDTYPE *, FIELDTYPE *); +int move_field(FIELD *, int, int); +FIELD *new_field(int, int, int, int, int, int); +FIELDTYPE *new_fieldtype(int (* field_check)(FIELD *, char *), + int (* char_check)(int, char *)); +FORM *new_form(FIELD **); +int new_page(FIELD *); +int pos_form_cursor(FORM *); +int post_form(FORM *); +int scale_form(FORM *, int *, int *); +int set_current_field(FORM *, FIELD *); +int set_field_back(FIELD *, chtype); +int set_field_buffer(FIELD *, int, char *); +int set_field_fore(FIELD *, chtype); +int set_field_init(FORM *, Form_Hook); +int set_field_just(FIELD *, int); +int set_field_opts(FIELD *, Form_Options); +int set_field_pad(FIELD *, int); +int set_field_printf(FIELD *, int, char *, ...) __printflike(3, 4); +int set_field_status(FIELD *, int); +int set_field_term(FORM *, Form_Hook); +int set_field_type(FIELD *, FIELDTYPE *, ...); +int set_field_userptr(FIELD *, void *); +int set_fieldtype_arg(FIELDTYPE *, char *(*)(va_list *), + char *(*)(char *), + void (*)(char *)); +int set_fieldtype_choice(FIELDTYPE *, int (*)(FIELD *, char *), + int (*)(FIELD *, char *)); +int set_form_fields(FORM *, FIELD **); +int set_form_init(FORM *, Form_Hook); +int set_form_opts(FORM *, Form_Options); +int set_form_page(FORM *, int); +int set_form_sub(FORM *, WINDOW *); +int set_form_term(FORM *, Form_Hook); +int set_form_userptr(FORM *, void *); +int set_form_win(FORM *, WINDOW *); +int set_max_field(FIELD *, int); +int set_new_page(FIELD *, int); +int unpost_form(FORM *); + +__END_DECLS + +#endif /* FORM_H */ diff --git a/lib/libform/form_cursor.3 b/lib/libform/form_cursor.3 new file mode 100644 index 000000000..dbb6a39d8 --- /dev/null +++ b/lib/libform/form_cursor.3 @@ -0,0 +1,71 @@ +.\" $NetBSD: form_cursor.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm pos_form_cursor +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn pos_form_cursor "FORM *form" +.Sh DESCRIPTION +The function +.Fn pos_form_cursor +positions the screen cursor at the correct position for the form. +This function can be used to restore the cursor state after using +other curses routines. +.Sh RETURN VALUES +.Fn pos_form_cursor +will return one of the following error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the function. +.It Er E_NOT_POSTED +The form is not posted to the screen. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_data.3 b/lib/libform/form_data.3 new file mode 100644 index 000000000..3fafd3ee8 --- /dev/null +++ b/lib/libform/form_data.3 @@ -0,0 +1,75 @@ +.\" $NetBSD: form_data.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORM_DATA 3 +.Os +.Sh NAME +.Nm form +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn data_ahead "FORM *form" +.Ft int +.Fn data_behind "FORM *form" +.Sh DESCRIPTION +If there is data offscreen to the right of the current field of the +given form then +.Fn data_ahead +will return +.Dv TRUE , +otherwise +.Dv FALSE +is returned. +Similarly, if there is +data offscreen to the left of the current field of the given form then +.Fn data_behind +will return +.Dv TRUE . +.Sh RETURN VALUES +If the condition is met then the functions will return +.Dv TRUE , +if there +is an error or there is no data offscreen the functions will return +.Dv FALSE . +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_driver.3 b/lib/libform/form_driver.3 new file mode 100644 index 000000000..3c18991a1 --- /dev/null +++ b/lib/libform/form_driver.3 @@ -0,0 +1,226 @@ +.\" $NetBSD: form_driver.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm form_driver +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn form_driver "FORM *form" "int request" +.Sh DESCRIPTION +The +.Fn form_driver +is the heart of the forms library, it takes commands in the +.Fa request +parameter that is either a request to the driver to perform some +action or is a character to be inserted into the current field. +The form driver will attempt to insert any printable character passed to +it into the current field. +This may or may not succeed depending on the state of the current field. +If the character passed is not +printable then the driver attempts to process it as a driver request. +If the character passed is not a valid request then the driver will +return an unknown command error. +.Sh PARAMETERS +The forms driver recognizes the following requests: +.Pp +.Bl -tag -width REQ_SFIRST_FIELD -compact +.It REQ_NEXT_PAGE +Change to the next page in the form. +.It REQ_PREV_PAGE +Change to the previous page in the form. +.It REQ_FIRST_PAGE +Select the first page in the form. +.It REQ_LAST_PAGE +Go to the last page in the form. +.It REQ_NEXT_FIELD +Move to the next field in the form field array. +.It REQ_PREV_FIELD +Move to the previous field in the form field array. +.It REQ_FIRST_FIELD +Go to the first field in the form field array. +.It REQ_LAST_FIELD +Go to the last field in the form field array. +.It REQ_SNEXT_FIELD +Move to the next sorted field on the form. +.It REQ_SPREV_FIELD +Move to the previous sorted field on the form. +.It REQ_SFIRST_FIELD +Go to the first field in the sorted list. +.It REQ_SLAST_FIELD +Move to the last field in the sorted list. +.It REQ_LEFT_FIELD +Go one field to the left on the form page. +.It REQ_RIGHT_FIELD +Go one field to the right on the form page. +.It REQ_UP_FIELD +Go up one field on the form page. +.It REQ_DOWN_FIELD +Go down one field on the form page. +.It REQ_NEXT_CHAR +Move one char to the right within the field +.It REQ_PREV_CHAR +Move one char to the left within the current field. +.It REQ_NEXT_LINE +Go down one line in the current field. +.It REQ_PREV_LINE +Go up one line in the current field. +.It REQ_NEXT_WORD +Go forward one word in the current field +.It REQ_PREV_WORD +Go backward one word in the current field. +.It REQ_BEG_FIELD +Move the cursor to the beginning of the current field. +.It REQ_END_FIELD +Move the cursor to the end of the current field. +.It REQ_BEG_LINE +Move the cursor to the beginning of the line in the current field. +.It REQ_END_LINE +Move the cursor to the end of the line. +.It REQ_LEFT_CHAR +Move the cursor left one character +.It REQ_RIGHT_CHAR +Move the cursor right one character +.It REQ_UP_CHAR +Move the cursor up one line. +.It REQ_DOWN_CHAR +Move the cursor down one line. +.It REQ_NEW_LINE +Insert a new line at the current cursor position. +.It REQ_INS_CHAR +Insert a blank character at the current cursor position +.It REQ_INS_LINE +Open a blank line at the current cursor position. +.It REQ_DEL_CHAR +Delete the character at the current cursor position. +.It REQ_DEL_PREV +Delete the character to the left of the current cursor position. +.It REQ_DEL_LINE +Delete the current line. +.It REQ_DEL_WORD +Delete the word at the current cursor position. +.It REQ_CLR_EOL +Clear the field from the current cursor position to the end of the +current line. +.It REQ_CLR_EOF +Clear the field from the current cursor position to the end of the field. +.It REQ_CLR_FIELD +Clear the field. +.It REQ_OVL_MODE +Enter overlay mode, characters added to the field will replace the +ones already there. +.It REQ_INS_MODE +Enter insert mode, characters will be inserted at the current cursor +position. +Any characters to the right of the cursor will be moved +right to accommodate the new characters. +.It REQ_SCR_FLINE +Scroll the field forward one line. +.It REQ_SCR_BLINE +Scroll the field backward one line. +.It REQ_SCR_FPAGE +Scroll the field forward one field page. +.It REQ_SCR_BPAGE +Scroll the field backward one field page. +.It REQ_SCR_FHPAGE +Scroll the field forward half one field page. +.It REQ_SCR_BHPAGE +Scroll the field backward half one field page. +.It REQ_SCR_FCHAR +Scroll the field horizontally forward one character +.It REQ_SCR_BCHAR +Scroll the field horizontally backward one character +.It REQ_SCR_HFLINE +Scroll the field horizontally forward one field line. +.It REQ_SCR_HBLINE +Scroll the field horizontally backward one field line. +.It REQ_SCR_HFHALF +Scroll the field horizontally forward half a field line. +.It REQ_SCR_HBHALF +Scroll the field horizontally backward half a field line. +.It REQ_VALIDATION +Request the contents of the current field be validated using any field +validation function that has been set for the field. +Normally, the field is validated before the current field changes. +This request allows the current field to be validated. +.It REQ_PREV_CHOICE +Select the previous choice in an enumerated type field. +.It REQ_NEXT_CHOICE +Select the next choice in an enumerated type field. +.El +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_REQUEST_DENIED +The forms driver request could not be fulfilled +.It Er E_UNKNOWN_COMMAND +The passed character is not a printable character and is not a valid +forms driver request. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the forms driver. +.It Er E_INVALID_FIELD +The form passed to the driver has no valid attached fields. +.It Er E_NOT_POSTED +The given form is not currently posted to the screen. +.It Er E_BAD_STATE +The forms driver was called from within an init or term function. +.It Er E_INVALID_FIELD +The character passed to the forms driver fails the character +validation for the current field. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +Field sorting is done by location of the field on the form page, the +fields are sorted by position starting with the top-most, left-most +field and progressing left to right. +For the purposes of sorting, the +fields top left corner is used as the sort criteria. +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field.3 b/lib/libform/form_field.3 new file mode 100644 index 000000000..4432bb2e8 --- /dev/null +++ b/lib/libform/form_field.3 @@ -0,0 +1,111 @@ +.\" $NetBSD: form_field.3,v 1.12 2012/10/08 18:15:09 njoly Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_count , +.Nm form_fields , +.Nm move_field , +.Nm set_form_fields +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn field_count "FORM *form" +.Ft FIELD ** +.Fn form_fields "FORM *form" +.Ft int +.Fn move_field "FIELD *field" "int frow" "int fcol" +.Ft int +.Fn set_form_fields "FORM *form" "FIELD **fields" +.Sh DESCRIPTION +The +.Fn field_count +function returns the number of fields that are attached to the given +form, if the form argument passed is +.Dv NULL +then +.Fn field_count +will return \-1. +The function +.Fn form_fields +will return a pointer to array of attach fields for the given form, +this array is not +.Dv NULL +terminated, fields may be attached to the given +form by calling +.Fn set_form_fields . +The +.Fa fields +argument in this function is a pointer to a +.Dv NULL +terminated array of +fields that will be attached to the form. +If there are already fields attached to the form then they will be +detached before the new fields are attached. +The new fields given must not be attached to any other form. +The +.Fn move_field +function will move the given field to the location specified by +.Fa frow +and +.Fa fcol . +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_CONNECTED +The field is connected to a form. +.It Er E_POSTED +The form is currently posted to the screen. +.It Er E_BAD_ARGUMENT +The function was passed a bad argument. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_attributes.3 b/lib/libform/form_field_attributes.3 new file mode 100644 index 000000000..11b1bab41 --- /dev/null +++ b/lib/libform/form_field_attributes.3 @@ -0,0 +1,100 @@ +.\" $NetBSD: form_field_attributes.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_back , +.Nm field_fore , +.Nm field_pad , +.Nm set_field_back , +.Nm set_field_fore , +.Nm set_field_pad +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft chtype +.Fn field_back "FIELD *field" +.Ft chtype +.Fn field_fore "FIELD *field" +.Ft int +.Fn field_pad "FIELD *field" +.Ft int +.Fn set_field_back "FIELD *field" "chtype attribute" +.Ft int +.Fn set_field_fore "FIELD *field" "chtype attribute" +.Ft int +.Fn set_field_pad "FIELD *field" "int pad" +.Sh DESCRIPTION +Calling the function +.Fn field_back +will return the character attributes that will be applied to a field +that is not the current field, these attributes can be set by the +.Fn set_field_back +function. +The +.Fn field_fore +function returns the character attributes that will be used to +indicate that a field is the currently active one on the form, this +attribute may be set by using the +.Fn set_field_fore +function. +The pad character for a field is the character that will be printed in all +field locations not occupied with actual field contents. +The pad character can be retrieved by calling the +.Fn field_pad +function, the pad character is set by using the +.Fn set_field_pad +function. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_buffer.3 b/lib/libform/form_field_buffer.3 new file mode 100644 index 000000000..7b17104fa --- /dev/null +++ b/lib/libform/form_field_buffer.3 @@ -0,0 +1,134 @@ +.\" $NetBSD: form_field_buffer.3,v 1.13 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 15, 2005 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_buffer , +.Nm field_status , +.Nm set_field_buffer , +.Nm set_field_printf , +.Nm set_field_status , +.Nm set_max_field +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft char * +.Fn field_buffer "FIELD *field" "int buffer" +.Ft int +.Fn field_status "FIELD *field" +.Ft int +.Fn set_field_buffer "FIELD *field" "int buffer" "char *value" +.Ft int +.Fn set_field_printf "FIELD *field" "int buffer" "char *fmt" "..." +.Ft int +.Fn set_field_status "FIELD *field" "int status" +.Ft int +.Fn set_max_field "FIELD *field" "int max" +.Sh DESCRIPTION +The +.Fn field_buffer +function returns the contents of the buffer number specified by +.Fa buffer +for the given field. +If the requested buffer number exceeds the +number of buffers attached to the field then +.Dv NULL +will be returned. +If the field option +.Dv O_REFORMAT +is enabled on the given field then +storage will be allocated to hold the reformatted buffer. +This storage must be release by calling +.Xr free 3 +when it is no longer required. +If the +.Dv O_REFORMAT +field option is not set then no extra storage is allocated. +The field buffer may be set by calling +.Fn set_field_buffer +which will set the given buffer number to the contents of the string +passed. +A buffer may also be set by calling +.Fn set_field_printf +which sets the buffer using the format arg +.Fa fmt +after being expanded using the subsequent arguments in the same manner +as +.Xr sprintf 3 +does. +Calling +.Fn field_status +will return the status of the first buffer attached to the field. +If the field has been modified then the function will return +.Dv TRUE +otherwise +.Dv FALSE +is returned, the status of the first buffer may be +programmatically set by calling +.Fn set_field_status . +The maximum growth of a dynamic field can be set by calling +.Fn set_max_field +which limits the fields rows if the field is a multiline field or the +fields columns if the field only has a single row. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +A bad parameter was passed to the function. +.It Er E_SYSTEM_ERROR +A system error occurred performing the function. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . +The function +.Fn set_field_printf +is a +.Nx +extension and must not be used in portable code. diff --git a/lib/libform/form_field_info.3 b/lib/libform/form_field_info.3 new file mode 100644 index 000000000..f299cf3b1 --- /dev/null +++ b/lib/libform/form_field_info.3 @@ -0,0 +1,89 @@ +.\" $NetBSD: form_field_info.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm dynamic_field_info , +.Nm field_info +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn dynamic_field_info "FIELD *field" "int *drows" "int *dcols" "int *max" +.Ft int +.Fn field_info "FIELD *field" "int *rows" "int *cols" "int *frow" "int *fcol" \ +"int *nrow" "int *nbuf" +.Sh DESCRIPTION +The function +.Fn dynamic_field_info +returns the sizing information for the field given. +The function will return the number of rows, columns and the maximum +growth of the field in the storage pointed to by the drows, dcols and max +parameters respectively. +Dynamic field information cannot be requested for the default field. +If the field given is not dynamic then +.Fn dynamic_field_info +will simply return the size of the actual field. +The +.Fn field_info +will return the number or rows, columns, field starting row, field +starting column, number of off screen rows and number of buffers in +.Fa rows , +.Fa cols , +.Fa frow , +.Fa fcol , +.Fa nrow +and +.Fa nbuf +respectively. +.Sh RETURN VALUES +The functions will return one of the following error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the function. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_just.3 b/lib/libform/form_field_just.3 new file mode 100644 index 000000000..e0e0dfbf6 --- /dev/null +++ b/lib/libform/form_field_just.3 @@ -0,0 +1,97 @@ +.\" $NetBSD: form_field_just.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_just , +.Nm set_field_just +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn field_just "FIELD *field" +.Ft int +.Fn set_field_just "FIELD *field" "int justification" +.Sh DESCRIPTION +Field justification is only applied to static fields, a dynamic field +will not be justified. +The default justification for a field is +NO_JUSTIFICATION. +The +.Fn field_just +will return the current justification value of the given field and the +justification may be set by calling the +.Fn set_field_just +function. +.Sh PARAMETERS +The following are the valid justifications for a field: +.Pp +.Bl -tag -width NO_JUSTIFICATION -compact +.It NO_JUSTIFICATION +No justification is to be applied to the field. +In practice, this is the same as JUSTIFY_LEFT. +.It JUSTIFY_RIGHT +The field will be right justified. +That is, the end of each line will +be butted up against the right hand side of the field. +.It JUSTIFY_LEFT +The field will be left justified. +That is, the start of each line +will be butted up against the left hand side of the field. +.It JUSTIFY_CENTER +The field will be centre justified, padding will be applied to either +end of the line to make the line centred in the field. +.El +.Sh RETURN VALUES +The functions will return one of the following error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_CURRENT +The field specified is the currently active one on the form. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the function. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_new.3 b/lib/libform/form_field_new.3 new file mode 100644 index 000000000..f3e4a1c84 --- /dev/null +++ b/lib/libform/form_field_new.3 @@ -0,0 +1,117 @@ +.\" $NetBSD: form_field_new.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm dup_field , +.Nm free_field , +.Nm link_field , +.Nm new_field +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft FIELD * +.Fn dup_field "FIELD *field" "int frow" "int fcol" +.Ft int +.Fn free_field "FIELD *field" +.Ft FIELD * +.Fn link_field "FIELD *field" "int frow" "int fcol" +.Ft FIELD * +.Fo new_field +.Fa "int rows" +.Fa "int cols" +.Fa "int frow" +.Fa "int fcol" +.Fa "int nrows" +.Fa "int nbuf" +.Fc +.Sh DESCRIPTION +The +.Fn dup_field +function duplicates the given field, including any buffers associated +with the field and returns the pointer to the newly created field. +.Fn free_field +destroys the field and frees any allocated resources associated with +the field. +The function +.Fn link_field +copies the given field to a new field at the location +.Fa frow +and +.Fa fcol +but shares the buffers with the original field. +.Fn new_field +creates a new field of size +.Fa rows +by +.Fa cols +at location +.Fa frow , +.Fa fcol +on the page, the argument +.Fa nrows +specified the number of off screen rows the field has and the +.Fa nbuf +parameter specifies the number of extra buffers attached to the +field. +There will always be one buffer associated with a field. +.Sh RETURN VALUES +On error +.Fn dup_field +and +.Fn new_field +will return +.Dv NULL . +The functions will one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the function. +.It Er E_CONNECTED +The field is connected to a form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_opts.3 b/lib/libform/form_field_opts.3 new file mode 100644 index 000000000..1de3e2adc --- /dev/null +++ b/lib/libform/form_field_opts.3 @@ -0,0 +1,157 @@ +.\" $NetBSD: form_field_opts.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 24, 2004 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_opts , +.Nm field_opts_off , +.Nm field_opts_on , +.Nm set_field_opts +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft Form_Options +.Fn field_opts "FIELD *field" +.Ft int +.Fn field_opts_off "FIELD *field" "Form_Options options" +.Ft int +.Fn field_opts_on "FIELD *field" "Form_Options options" +.Ft int +.Fn set_field_opts "FIELD *field" "Form_Options options" +.Sh DESCRIPTION +The function +.Fn field_opts +returns the current options settings for the given field. +The +.Fn field_opts_off +will turn the options given in +.Fa options +off for the given field, options not specified in +.Fa options +will remain unchanged. +Conversely, the function +.Fn field_opts_on +will turn on the options given in +.Fa options +for the specified field, again, any options not specified will remain +unchanged. +The options for a field may be set to a specific set of +options by calling the +.Fn set_field_opts +function. +Options may only be changed if the field given is not the +currently active one. +.Sh PARAMETERS +The following options are available for a field: +.Pp +.Bl -tag -width O_REFORMAT -compact +.It Dv O_VISIBLE +The field is visible, hence is displayed when the form is posted. +.It Dv O_ACTIVE +The field is active in the form, meaning that it can be visited during +form processing. +.It Dv O_PUBLIC +The contents of the field are echoed to the screen. +.It Dv O_EDIT +The contents of the field can be modified +.It Dv O_WRAP +The contents of the field are wrapped on a word boundary, if this +option is off then the field will be wrapped on a character boundary. +.It Dv O_BLANK +Blank the field on new data being entered if and only if the field +cursor is at the left hand side of the field. +.It Dv O_AUTOSKIP +Skip to the next field when the current field reaches its maximum +size. +.It Dv O_NULLOK +The field is allowed to contain no data +.It Dv O_STATIC +The field is not dynamic, it has a fixed size. +.It Dv O_PASSOK +An unmodified field is allowed. +.It Dv O_REFORMAT +Retain the formatting of a field when the buffer is retrieved. +If this option is not set then the buffer returned will be a single string +with no line breaks. +When this option is set newline characters will be inserted at the point +where the string has been wrapped in a multiline field. +This option is an extension to the forms library and must not be used +in portable code. +See the +.Xr field_buffer 3 +man page for how this option modifies the behaviour of +.Fn field_buffer . +.El +.Pp +The following options are on by default for a field: +.Dv O_VISIBLE , +.Dv O_ACTIVE , +.Dv O_PUBLIC , +.Dv O_EDIT , +.Dv O_WRAP , +.Dv O_BLANK , +.Dv O_AUTOSKIP , +.Dv O_NULLOK , +.Dv O_PASSOK , +and +.Dv O_STATIC . +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_CURRENT +The field specified is the currently active one in the form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . +The option +.Dv O_REFORMAT +is a +.Nx + extension and must not be used in portable code. diff --git a/lib/libform/form_field_userptr.3 b/lib/libform/form_field_userptr.3 new file mode 100644 index 000000000..4aff31cbf --- /dev/null +++ b/lib/libform/form_field_userptr.3 @@ -0,0 +1,74 @@ +.\" $NetBSD: form_field_userptr.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_userptr , +.Nm set_field_userptr +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft void * +.Fn field_userptr "FIELD *field" +.Ft int +.Fn set_field_userptr "FIELD *field" "void *ptr" +.Sh DESCRIPTION +The +.Fn field_userptr +function returns the pointer to the user defined data for the field, +this pointer may be set by calling the +.Fn set_field_userptr +function. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_field_validation.3 b/lib/libform/form_field_validation.3 new file mode 100644 index 000000000..928896e22 --- /dev/null +++ b/lib/libform/form_field_validation.3 @@ -0,0 +1,82 @@ +.\" $NetBSD: form_field_validation.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_arg , +.Nm field_type , +.Nm set_field_type +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft char * +.Fn field_arg "FIELD *field" +.Ft FIELDTYPE * +.Fn field_type "FIELD *field" +.Ft int +.Fn set_field_type "FIELD *field" "FIELDTYPE *type" "..." +.Sh DESCRIPTION +The +.Fn field_arg +function returns the field type arguments that are associated with the +given field. +The +.Fn field_type +function returns the field type structure associated with the given +field, this type can be set by calling the +.Fn set_field_type +function which associates the given field type with the field, the +third and subsequent parameters are field dependent arguments. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_fieldtype.3 b/lib/libform/form_fieldtype.3 new file mode 100644 index 000000000..c4faa0b0c --- /dev/null +++ b/lib/libform/form_fieldtype.3 @@ -0,0 +1,150 @@ +.\" $NetBSD: form_fieldtype.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm free_fieldtype , +.Nm link_fieldtype , +.Nm new_fieldtype , +.Nm set_fieldtype_arg , +.Nm set_fieldtype_choice +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn free_fieldtype "FIELDTYPE *fieldtype" +.Ft FIELDTYPE * +.Fn link_fieldtype "FIELDTYPE *type1" "FIELDTYPE *type2" +.Ft FIELDTYPE * +.Fo new_fieldtype +.Fa "int (*field_check)(FIELD *, char *)" +.Fa "int (*char_check)(int, char *)" +.Fc +.Ft int +.Fo "set_fieldtype_arg" +.Fa "FIELDTYPE *fieldtype" +.Fa "char * (*make_args)(va_list *)" +.Fa "char * (*copy_args)(char *)" +.Fa "void (*free_args)(char *)" +.Fc +.Ft int +.Fo set_fieldtype_choice +.Fa "FIELDTYPE *fieldtype" +.Fa "int (*next_choice)(FIELD *, char *)" +.Fa "int (*prev_choice)(FIELD *, char *)" +.Fc +.Sh DESCRIPTION +The function +.Fn free_fieldtype +frees the storage associated with the field type and destroys it. +The function +.Fn link_fieldtype +links together the two given field types to produce a new field type. +A new field type can be created by calling +.Fn new_fieldtype +which requires pointers to two functions which perform validation, the +.Fa field_check +function must validate the field contents and return +.Dv TRUE +if they are acceptable and +.Dv FALSE +if they are not. +The +.Fa char_check +validates the character input into the field, this function will be +called for each character entered, if the character can be entered +into the field then +.Fa char_check +must return +.Dv TRUE . +Neither +.Fa field_check +nor +.Fa char_check +may be +.Dv NULL . +The functions for handling the field type arguments can +be defined by using the +.Fn set_fieldtype_arg +function, the +.Fa make_args +function is used to create new arguments for the fieldtype, the +.Fa copy_args +is used to copy the fieldtype arguments to a new arguments structure +and +.Fa free_args +is used to destroy the fieldtype arguments and release any associated +storage, none of these function pointers may be +.Dv NULL . +The field type choice functions can be set by calling +.Fn set_fieldtype_choice , +the +.Fa next_choice +and +.Fa prev_choice +specify the next and previous choice functions for the field type. +These functions must perform the necessary actions to select the next +or previous choice for the field, updating the field buffer if +necessary. +The choice functions must return +.Dv TRUE +if the function succeeded and +.Dv FALSE +otherwise. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +The function was passed a bad argument. +.It Er E_CONNECTED +The field is connected to a form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_hook.3 b/lib/libform/form_hook.3 new file mode 100644 index 000000000..2c7045502 --- /dev/null +++ b/lib/libform/form_hook.3 @@ -0,0 +1,116 @@ +.\" $NetBSD: form_hook.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm field_init , +.Nm field_term , +.Nm form_init , +.Nm form_term , +.Nm set_field_init , +.Nm set_field_term , +.Nm set_form_init , +.Nm set_form_term +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft void (*)(FORM *) +.Fn field_init "FORM *form" +.Ft void (*)(FORM *) +.Fn field_term "FORM *form" +.Ft void (*)(FORM *) +.Fn form_init "FORM *form" +.Ft void (*)(FORM *) +.Fn form_term "FORM *form" +.Ft int +.Fn set_field_init "FORM *form" "void (*function)(FORM *)" +.Ft int +.Fn set_field_term "FORM *form" "void (*function)(FORM *)" +.Ft int +.Fn set_form_init "FORM *form" "void (*function)(FORM *)" +.Ft int +.Fn set_form_term "FORM *form" "void (*function)(FORM *)" +.Sh DESCRIPTION +The +.Fn field_init +function returns a pointer to the function that will be called just +after the current field changes and just before the form is posted, +this function may be set by using the +.Fn set_field_init +function. +Similarly, the function +.Fn field_term +will return a pointer to the function that will be called just before +the current field changes and just after the form is unposted, this +function pointer may be set by using the +.Fn set_field_term +function. +The +.Fn form_init +function will return a pointer to the function that will be called +just before the form is posted to the screen, this function can be set +by calling the +.Fn set_form_init +function. +The +.Fn form_term +function will return a pointer to the function that will be called +just after the form is unposted from the screen, this function may be +set by using the +.Fn set_form_term +function. +By default, the init and term function pointers are +.Dv NULL . +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_new.3 b/lib/libform/form_new.3 new file mode 100644 index 000000000..7d4b84128 --- /dev/null +++ b/lib/libform/form_new.3 @@ -0,0 +1,85 @@ +.\" $NetBSD: form_new.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm free_form , +.Nm new_form +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn free_form "FORM *form" +.Ft FORM * +.Fn new_form "FIELD **fields" +.Sh DESCRIPTION +The function +.Fn free_form +frees all the resources associated with the form and destroys the +form. +Calling +.Fn new_form +will create a new form, set the form parameters to the current +defaults and attach the passed fields to the form. +The array of fields passed to +.Fn new_form +must be terminated with a +.Dv NULL +pointer to indicate the end of the fields. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +The function was passed a bad argument. +.It Er E_POSTED +The form is posted to the screen. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_new_page.3 b/lib/libform/form_new_page.3 new file mode 100644 index 000000000..0a1ae42f1 --- /dev/null +++ b/lib/libform/form_new_page.3 @@ -0,0 +1,75 @@ +.\" $NetBSD: form_new_page.3,v 1.11 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm new_page , +.Nm set_new_page +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn new_page "FIELD *field" +.Ft int +.Fn set_new_page "FIELD *field" "int page" +.Sh DESCRIPTION +The +.Fn new_page +function returns +.Dv TRUE +if the given field is the start of a new page, otherwise it returns +.Dv FALSE , +the new page status of a field can be set or unset using the +.Fn set_new_page +function. +.Sh RETURN VALUES +The functions will return one of the following error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_CONNECTED +The field is connected to a form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_opts.3 b/lib/libform/form_opts.3 new file mode 100644 index 000000000..180d16071 --- /dev/null +++ b/lib/libform/form_opts.3 @@ -0,0 +1,104 @@ +.\" $NetBSD: form_opts.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm form_opts , +.Nm form_opts_off , +.Nm form_opts_on , +.Nm set_form_opts +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft Form_Options +.Fn form_opts "FORM *form" +.Ft int +.Fn form_opts_off "FORM *form" "Form_Options options" +.Ft int +.Fn form_opts_on "FORM *form" "Form_Options options" +.Ft int +.Fn set_form_opts "FORM *form" "Form_Options options" +.Sh DESCRIPTION +The function +.Fn form_opts +returns the current options that are set on the given form. +The +.Fn form_opts_off +will turn off the form options given in +.Fa options +for the form, similarly, +.Fn form_opts_on +will turn on the options specified in +.Fa options +for the given form. +The form options can be set to an explicit set by calling +.Fn set_form_opts . +.Sh PARAMETERS +The following form options are valid: +.Pp +.Bl -tag -width O_BS_OVERLOAD -compact +.It O_BS_OVERLOAD +If this option is set and the cursor is at the first character in the +field then the backspace character will perform the same function as a +REQ_PREV_FIELD driver request, moving to the previous field in the +form. +.It O_NL_OVERLOAD +If this option is set and the cursor is at the end of the field then +the new line character will perform the same function as a +REQ_NEXT_FIELD driver request, moving to the next field in the form. +.El +.Pp +By default no form options are set. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_page.3 b/lib/libform/form_page.3 new file mode 100644 index 000000000..39a59e3bc --- /dev/null +++ b/lib/libform/form_page.3 @@ -0,0 +1,119 @@ +.\" $NetBSD: form_page.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 1999 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORM_PAGE 3 +.Os +.Sh NAME +.Nm current_field , +.Nm field_index , +.Nm form_page , +.Nm form_max_page , +.Nm set_current_field , +.Nm set_form_page +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft FIELD * +.Fn current_field "FORM *form" +.Ft int +.Fn field_index "FIELD *field" +.Ft int +.Fn form_page "FORM *form" +.Ft int +.Fn form_max_page "FORM *form" +.Ft int +.Fn set_current_field "FORM *form" "FIELD *field" +.Ft int +.Fn set_form_page "FORM *form" "int page" +.Sh DESCRIPTION +The +.Fn current_field +returns a pointer to the structure for the field that is currently +active on the page. +If there is an error, +.Fn current_field +will return +.Dv NULL . +Calling +.Fn field_index +will return the index of the given field in the form field array. +The +current page the form is on can be determined by using +.Fn form_page , +the current page of a form can be programmatically set by calling +.Fn set_form_page . +The maximum page number for a form can be found by +calling the function +.Fn form_max_page +but note that this function is a +.Nx +extension and must not be used in portable forms library programs. +The current field on the form may be set by calling +.Fn set_current_field +which will set the current field to the one given. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following +error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +The function was passed a bad argument. +.It Er E_NOT_CONNECTED +The given field is not associated with a form. +.It Er E_BAD_STATE +The function was called from within an init or term function. +.It Er E_INVALID_FIELD +The field given is not part of the given form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . +.Pp +The +.Nm form_max_page +is a +.Nx +extension and should not be used in portable applications. diff --git a/lib/libform/form_post.3 b/lib/libform/form_post.3 new file mode 100644 index 000000000..ed71b5f37 --- /dev/null +++ b/lib/libform/form_post.3 @@ -0,0 +1,85 @@ +.\" $NetBSD: form_post.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm post_form , +.Nm unpost_form +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft int +.Fn post_form "FORM *form" +.Ft int +.Fn unpost_form "FORM *form" +.Sh DESCRIPTION +The +.Fn post_form +function performs the actions necessary to present the form on the +curses screen. +If there are any init functions that need to be called +then they will be called prior to the form being posted and the cursor +will be positioned on the first active field that can be visited. +Conversely, the function +.Fn unpost_form +removes the form from the screen and calls any termination functions +that were specified. +.Sh RETURN VALUES +The functions will return one of the following error values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_BAD_ARGUMENT +A bad argument was passed to the function. +.It Er E_POSTED +The form is already posted to the screen. +.It Er E_NOT_POSTED +The form was not posted to the screen. +.It Er E_NOT_CONNECTED +There are no fields associated with the form. +.It Er E_BAD_STATE +The function was called from within a init or term function. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_userptr.3 b/lib/libform/form_userptr.3 new file mode 100644 index 000000000..0fc421209 --- /dev/null +++ b/lib/libform/form_userptr.3 @@ -0,0 +1,74 @@ +.\" $NetBSD: form_userptr.3,v 1.9 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm form_userptr , +.Nm set_form_userptr +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft void * +.Fn form_userptr "FORM *form" +.Ft int +.Fn set_form_userptr "FORM *form" "void *ptr" +.Sh DESCRIPTION +The +.Fn form_userptr +function returns the pointer to the user defined data associated with +the form, this pointer may be set using the +.Fn set_form_userptr +call. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/form_win.3 b/lib/libform/form_win.3 new file mode 100644 index 000000000..0d065f209 --- /dev/null +++ b/lib/libform/form_win.3 @@ -0,0 +1,109 @@ +.\" $NetBSD: form_win.3,v 1.10 2010/03/22 21:58:31 joerg Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2001 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm form_sub , +.Nm form_win , +.Nm scale_form , +.Nm set_form_sub , +.Nm set_form_win +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Ft WINDOW * +.Fn form_sub "FORM *form" +.Ft WINDOW * +.Fn form_win "FORM *form" +.Ft int +.Fn scale_form "FORM *form" "int *rows" "int *cols" +.Ft int +.Fn set_form_sub "FORM *form" "WINDOW *window" +.Ft int +.Fn set_form_win "FORM *form" "WINDOW *window" +.Sh DESCRIPTION +All output to the screen done by the forms library is handled by the +curses library routines. +By default, the forms library will output to the curses +.Fa stdscr , +but if the forms window has been set via +.Fn set_form_win +then output will be sent to the window specified by +.Fn set_form_win , +unless the forms subwindow has been set using +.Fn set_form_sub . +If a subwindow has been specified using +.Fn set_form_sub +then it will be used by the forms library to for screen output. +The current setting for the form window can be retrieved by calling +.Fn form_win . +If the forms window has not been set then +.Dv NULL +will be returned. +Similarly, the forms subwindow can be found by calling the +.Fn form_sub +function, again, if the subwindow has not been set then +.Dv NULL +will be +returned. +The +.Fn scale_form +function will return the minimum number of rows and columns that will +entirely contain the given form. +.Sh RETURN VALUES +Functions returning pointers will return +.Dv NULL +if an error is detected. +The functions that return an int will return one of the following error +values: +.Pp +.Bl -tag -width E_UNKNOWN_COMMAND -compact +.It Er E_OK +The function was successful. +.It Er E_NOT_CONNECTED +The form has no fields connected to it. +.It Er E_POSTED +The form is posted to the screen. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr forms 3 +.Sh NOTES +The header +.In form.h +automatically includes both +.In curses.h +and +.In eti.h . diff --git a/lib/libform/forms.3 b/lib/libform/forms.3 new file mode 100644 index 000000000..6be7ae3a7 --- /dev/null +++ b/lib/libform/forms.3 @@ -0,0 +1,235 @@ +.\" $NetBSD: forms.3,v 1.16 2004/11/24 12:09:13 wiz Exp $ +.\" +.\" Copyright (c) 2001 +.\" Brett Lymn - blymn@baea.com.au, brett_lymn@yahoo.com.au +.\" +.\" This code is donated to The NetBSD Foundation by the author. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the Author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 24, 2004 +.Dt FORMS 3 +.Os +.Sh NAME +.Nm form +.Nd form library +.Sh LIBRARY +.Lb libform +.Sh SYNOPSIS +.In form.h +.Sh DESCRIPTION +The +.Nm +library provides a terminal independent form system using the +.Xr curses 3 +library. +Before using the +.Nm +functions the terminal must be set up by +.Xr curses 3 +using the +.Fn initscr +function or similar. +Programs using +.Nm +functions must be linked with the +.Xr curses 3 +library +.Fl lcurses . +.Pp +The +.Nm +library provides facilities for defining form fields, placing a form on the +terminal screen, assign pre and post change operations and setting the +attributes of both the form and its fields. +.Ss Defining default attributes for forms and fields +The +.Nm +library allows any settable attribute or option of both the form and field +objects to be defined such that any new form or field automatically inherits +the value as default. +Setting the default value will not affect any field or +form that has already been created but will be applied to subsequent objects. +To set the default attribute or option the set routine is passed a +.Dv NULL +pointer in the field or form parameter when calling the set routine. +The current default value can be retrieved by calling the get routine with a +.Dv NULL +pointer for the field or form parameter. +.Pp +.Bl -column set_fieldtype_choiceXX +.It Sy "Form Routine Name" Ta Sy "Manual Page Name" +.It current_field Ta Xr form_page 3 +.It data_ahead Ta Xr form_data 3 +.It data_behind Ta Xr form_data 3 +.It dup_field Ta Xr form_field_new 3 +.It dynamic_field_info Ta Xr form_field_info 3 +.It field_arg Ta Xr form_field_validation 3 +.It field_back Ta Xr form_field_attributes 3 +.It field_buffer Ta Xr form_field_buffer 3 +.It field_count Ta Xr form_field 3 +.It field_fore Ta Xr form_field_attributes 3 +.It field_index Ta Xr form_page 3 +.It field_info Ta Xr form_field_info 3 +.It field_init Ta Xr form_hook 3 +.It field_just Ta Xr form_field_just 3 +.It field_opts Ta Xr form_field_opts 3 +.It field_opts_off Ta Xr form_field_opts 3 +.It field_opts_on Ta Xr form_field_opts 3 +.It field_pad Ta Xr form_field_attributes 3 +.It field_status Ta Xr form_field_buffer 3 +.It field_term Ta Xr form_hook 3 +.It field_type Ta Xr form_field_validation 3 +.It field_userptr Ta Xr form_field_userptr 3 +.It form_driver Ta Xr form_driver 3 +.It form_fields Ta Xr form_field 3 +.It form_init Ta Xr form_hook 3 +.It form_max_page Ta Xr form_page 3 +.It form_opts Ta Xr form_opts 3 +.It form_opts_off Ta Xr form_opts 3 +.It form_opts_on Ta Xr form_opts 3 +.It form_page Ta Xr form_page 3 +.It form_sub Ta Xr form_win 3 +.It form_term Ta Xr form_hook 3 +.It form_userptr Ta Xr form_userptr 3 +.It form_win Ta Xr form_win 3 +.It free_field Ta Xr form_field_new 3 +.It free_fieldtype Ta Xr form_fieldtype 3 +.It free_form Ta Xr form_new 3 +.It link_field Ta Xr form_field_new 3 +.It link_fieldtype Ta Xr form_fieldtype 3 +.It move_field Ta Xr form_field 3 +.It new_field Ta Xr form_field_new 3 +.It new_fieldtype Ta Xr form_fieldtype 3 +.It new_form Ta Xr form_new 3 +.It new_page Ta Xr form_new_page 3 +.It pos_form_cursor Ta Xr form_cursor 3 +.It post_form Ta Xr form_post 3 +.It scale_form Ta Xr form_win 3 +.It set_current_field Ta Xr form_page 3 +.It set_field_back Ta Xr form_field_attributes 3 +.It set_field_buffer Ta Xr form_field_buffer 3 +.It set_field_fore Ta Xr form_field_attributes 3 +.It set_field_init Ta Xr form_hook 3 +.It set_field_just Ta Xr form_field_just 3 +.It set_field_opts Ta Xr form_field_opts 3 +.It set_field_pad Ta Xr form_field_attributes 3 +.It set_field_printf Ta Xr form_field_buffer 3 +.It set_field_status Ta Xr form_field_buffer 3 +.It set_field_term Ta Xr form_hook 3 +.It set_field_type Ta Xr form_field_validation 3 +.It set_field_userptr Ta Xr form_field_userptr 3 +.It set_fieldtype_arg Ta Xr form_fieldtype 3 +.It set_fieldtype_choice Ta Xr form_fieldtype 3 +.It set_form_fields Ta Xr form_field 3 +.It set_form_init Ta Xr form_hook 3 +.It set_form_opts Ta Xr form_opts 3 +.It set_form_page Ta Xr form_page 3 +.It set_form_sub Ta Xr form_win 3 +.It set_form_term Ta Xr form_hook 3 +.It set_form_userptr Ta Xr form_userptr 3 +.It set_form_win Ta Xr form_win 3 +.It set_max_field Ta Xr form_field_buffer 3 +.It set_new_page Ta Xr form_new_page 3 +.It unpost_form Ta Xr form_post 3 +.El +.Sh RETURN VALUES +Any function returning a string pointer will return +.Dv NULL +if an error occurs. +Functions returning an integer will return one of the following: +.Bl -column set_fieldtype_choiceXX +.It Dv E_OK Ta No The function was successful. +.It Dv E_SYSTEM_ERROR Ta No There was a system error during the call. +.It Dv E_BAD_ARGUMENT Ta No One or more of the arguments passed to \ +the function was incorrect. +.It Dv E_POSTED Ta No The form is already posted. +.It Dv E_CONNECTED Ta No A field was already connected to a form. +.It Dv E_BAD_STATE Ta No The function was called from within an \ +initialization or termination routine. +.It Dv E_NO_ROOM Ta No The form does not fit within the subwindow. +.It Dv E_NOT_POSTED Ta No The form is not posted. +.It Dv E_UNKNOWN_COMMAND Ta No The form driver does not recognize the \ +request passed to it. +.It Dv E_NOT_SELECTABLE Ta No The field could not be selected. +.It Dv E_NOT_CONNECTED Ta No The field is not connected to a form. +.It Dv E_REQUEST_DENIED Ta No The form driver could not process the request. +.It Dv E_INVALID_FIELD Ta No The field is invalid. +.It Dv E_CURRENT Ta No The field is the active one on the form. +.El +.Sh SEE ALSO +.Xr curses 3 , +.Xr menus 3 +.Sh NOTES +This implementation of the forms library does depart in behavior +subtly from the original AT\*[Am]T implementation. +Some of the more notable departures are: +.Pp +.Bl -tag -width "The TAB character" -compact +.It field wrapping +For multi-line fields the data will be wrapped as it is entered, this +does not happen in the AT\*[Am]T implementation. +.It buffer 0 +In this implementation, the contents of buffer 0 are always current +regardless of whether the field has been validated or not. +.It circular fields +In the AT\*[Am]T implementation fields are circular on a page, that is, a +next field from the last field will go to the first field on the +current page. +In this implementation a next field request on the last +field of a page will result in the forms library positioning the +cursor on the first field of the next page. +If the field is the last +field in the form then going to the next field will be denied, in the +AT\*[Am]T it would result in the cursor being placed on the first field of +the first page. +.It buffer returns +In this implementation only the data entered by the user in the form +field will be returned, unlike the AT\*[Am]T library which would return the +contents of the field padded to the size of the field with the pad +character. +.It The TAB character +The handling of the TAB character in fields varies between +implementations. +In ncurses attempting to set a field contents with a +string containing a TAB will result in an error and will not allow a +TAB to be entered into a field. +The AT\*[Am]T library statically +converts tabs to the equivalent number of spaces when the field buffer +is set but the form driver will not allow a TAB to be inserted into +the field buffer. +This implementation allows TAB when setting the +field buffer and also will allow TAB to be inserted into a field +buffer via the form driver and correctly calculates the cursor +position allowing for expansion of the TAB character. +.It set_field_printf +This function is a +.Nx +extension and must not be used in portable code. +.It Dv O_REFORMAT +This field option is a +.Nx +extension and must not be used in portable code. +.El diff --git a/lib/libform/gdbinit b/lib/libform/gdbinit new file mode 100644 index 000000000..6a8d4231d --- /dev/null +++ b/lib/libform/gdbinit @@ -0,0 +1,20 @@ +# +# Print out the line structs +# +define lstructs + set $lstruct=(_FORMI_FIELD_LINES *)$arg0 + while ($lstruct) + print *($lstruct) + if ($lstruct->prev != 0x0) + if ($lstruct->prev->next != $lstruct) + print "WARNING: backward pointers inconsistent" + end + end + if ($lstruct->next != 0x0) + if ($lstruct->next->prev != $lstruct) + print "WARNING: forward pointers inconsistent" + end + end + set $lstruct = $lstruct->next + end +end diff --git a/lib/libform/internals.c b/lib/libform/internals.c new file mode 100644 index 000000000..e7a68c3be --- /dev/null +++ b/lib/libform/internals.c @@ -0,0 +1,3651 @@ +/* $NetBSD: internals.c,v 1.35 2011/05/23 20:43:02 joerg Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: internals.c,v 1.35 2011/05/23 20:43:02 joerg Exp $"); + +#include +#include +#include +#include +#include +#include +#include "internals.h" +#include "form.h" + +#ifdef DEBUG +/* + * file handle to write debug info to, this will be initialised when + * the form is first posted. + */ +FILE *dbg = NULL; + +/* + * map the request numbers to strings for debug + */ +char *reqs[] = { + "NEXT_PAGE", "PREV_PAGE", "FIRST_PAGE", "LAST_PAGE", "NEXT_FIELD", + "PREV_FIELD", "FIRST_FIELD", "LAST_FIELD", "SNEXT_FIELD", + "SPREV_FIELD", "SFIRST_FIELD", "SLAST_FIELD", "LEFT_FIELD", + "RIGHT_FIELD", "UP_FIELD", "DOWN_FIELD", "NEXT_CHAR", "PREV_CHAR", + "NEXT_LINE", "PREV_LINE", "NEXT_WORD", "PREV_WORD", "BEG_FIELD", + "END_FIELD", "BEG_LINE", "END_LINE", "LEFT_CHAR", "RIGHT_CHAR", + "UP_CHAR", "DOWN_CHAR", "NEW_LINE", "INS_CHAR", "INS_LINE", + "DEL_CHAR", "DEL_PREV", "DEL_LINE", "DEL_WORD", "CLR_EOL", + "CLR_EOF", "CLR_FIELD", "OVL_MODE", "INS_MODE", "SCR_FLINE", + "SCR_BLINE", "SCR_FPAGE", "SCR_BPAGE", "SCR_FHPAGE", "SCR_BHPAGE", + "SCR_FCHAR", "SCR_BCHAR", "SCR_HFLINE", "SCR_HBLINE", "SCR_HFHALF", + "SCR_HBHALF", "VALIDATION", "PREV_CHOICE", "NEXT_CHOICE" }; +#endif + +/* define our own min function - this is not generic but will do here + * (don't believe me? think about what value you would get + * from min(x++, y++) + */ +#define min(a,b) (((a) > (b))? (b) : (a)) + +/* for the line joining function... */ +#define JOIN_NEXT 1 +#define JOIN_NEXT_NW 2 /* next join, don't wrap the joined line */ +#define JOIN_PREV 3 +#define JOIN_PREV_NW 4 /* previous join, don't wrap the joined line */ + +/* for the bump_lines function... */ +#define _FORMI_USE_CURRENT -1 /* indicates current cursor pos to be used */ + +/* used in add_char for initial memory allocation for string in row */ +#define INITIAL_LINE_ALLOC 16 + +unsigned +field_skip_blanks(unsigned int start, _FORMI_FIELD_LINES **rowp); +static void +_formi_do_char_validation(FIELD *field, FIELDTYPE *type, char c, int *ret_val); +static void +_formi_do_validation(FIELD *field, FIELDTYPE *type, int *ret_val); +static int +_formi_join_line(FIELD *field, _FORMI_FIELD_LINES **rowp, int direction); +void +_formi_hscroll_back(FIELD *field, _FORMI_FIELD_LINES *row, unsigned int amt); +void +_formi_hscroll_fwd(FIELD *field, _FORMI_FIELD_LINES *row, unsigned int amt); +static void +_formi_scroll_back(FIELD *field, unsigned int amt); +static void +_formi_scroll_fwd(FIELD *field, unsigned int amt); +static int +_formi_set_cursor_xpos(FIELD *field, int no_scroll); +static int +find_sow(unsigned int offset, _FORMI_FIELD_LINES **rowp); +static int +split_line(FIELD *field, bool hard_split, unsigned pos, + _FORMI_FIELD_LINES **rowp); +static bool +check_field_size(FIELD *field); +static int +add_tab(FORM *form, _FORMI_FIELD_LINES *row, unsigned int i, char c); +static int +tab_size(_FORMI_FIELD_LINES *row, unsigned int i); +static unsigned int +tab_fit_len(_FORMI_FIELD_LINES *row, unsigned int len); +static int +tab_fit_window(FIELD *field, unsigned int pos, unsigned int window); +static void +add_to_free(FIELD *field, _FORMI_FIELD_LINES *line); +static void +adjust_ypos(FIELD *field, _FORMI_FIELD_LINES *line); +static _FORMI_FIELD_LINES * +copy_row(_FORMI_FIELD_LINES *row); +static void +destroy_row_list(_FORMI_FIELD_LINES *start); + +/* + * Calculate the cursor y position to make the given row appear on the + * field. This may be as simple as just changing the ypos (if at all) but + * may encompass resetting the start_line of the field to place the line + * at the bottom of the field. The field is assumed to be a multi-line one. + */ +static void +adjust_ypos(FIELD *field, _FORMI_FIELD_LINES *line) +{ + unsigned ypos; + _FORMI_FIELD_LINES *rs; + + ypos = 0; + rs = field->alines; + while (rs != line) { + rs = rs->next; + ypos++; + } + + field->cursor_ypos = ypos; + field->start_line = field->alines; + if (ypos > (field->rows - 1)) { + /* + * cur_line off the end of the field, + * adjust start_line so fix this. + */ + field->cursor_ypos = field->rows - 1; + ypos = ypos - (field->rows - 1); + while (ypos > 0) { + ypos--; + field->start_line = field->start_line->next; + } + } +} + + +/* + * Delete the given row and add it to the free list of the given field. + */ +static void +add_to_free(FIELD *field, _FORMI_FIELD_LINES *line) +{ + _FORMI_FIELD_LINES *saved; + + saved = line; + + /* don't remove if only one line... */ + if ((line->prev == NULL) && (line->next == NULL)) + return; + + if (line->prev == NULL) { + /* handle top of list */ + field->alines = line->next; + field->alines->prev = NULL; + + if (field->cur_line == saved) + field->cur_line = field->alines; + if (field->start_line == saved) + field->start_line = saved; + } else if (line->next == NULL) { + /* handle bottom of list */ + line->prev->next = NULL; + if (field->cur_line == saved) + field->cur_line = saved->prev; + if (field->start_line == saved) + field->cur_line = saved->prev; + } else { + saved->next->prev = saved->prev; + saved->prev->next = saved->next; + if (field->cur_line == saved) + field->cur_line = saved->prev; + if (field->start_line == saved) + field->start_line = saved; + } + + saved->next = field->free; + field->free = saved; + saved->prev = NULL; + if (saved->next != NULL) + saved->next->prev = line; +} + +/* + * Duplicate the given row, return the pointer to the new copy or + * NULL if the copy fails. + */ +static _FORMI_FIELD_LINES * +copy_row(_FORMI_FIELD_LINES *row) +{ + _FORMI_FIELD_LINES *new; + _formi_tab_t *tp, *newt; + + if ((new = (_FORMI_FIELD_LINES *) malloc(sizeof(_FORMI_FIELD_LINES))) + == NULL) { + return NULL; + } + + memcpy(new, row, sizeof(_FORMI_FIELD_LINES)); + + /* nuke the pointers from the source row so we don't get confused */ + new->next = NULL; + new->prev = NULL; + new->tabs = NULL; + + if ((new->string = (char *) malloc((size_t)new->allocated)) == NULL) { + free(new); + return NULL; + } + + memcpy(new->string, row->string, (size_t) row->length + 1); + + if (row->tabs != NULL) { + tp = row->tabs; + if ((new->tabs = (_formi_tab_t *) malloc(sizeof(_formi_tab_t))) + == NULL) { + free(new->string); + free(new); + return NULL; + } + + memcpy(new->tabs, row->tabs, sizeof(_formi_tab_t)); + new->tabs->back = NULL; + new->tabs->fwd = NULL; + + tp = tp->fwd; + newt = new->tabs; + + while (tp != NULL) { + if ((newt->fwd = + (_formi_tab_t *) malloc(sizeof(_formi_tab_t))) + == NULL) { + /* error... unwind allocations */ + tp = new->tabs; + while (tp != NULL) { + newt = tp->fwd; + free(tp); + tp = newt; + } + + free(new->string); + free(new); + return NULL; + } + + memcpy(newt->fwd, tp, sizeof(_formi_tab_t)); + newt->fwd->back = newt; + newt = newt->fwd; + newt->fwd = NULL; + tp = tp->fwd; + } + } + + return new; +} + +/* + * Initialise the row offset for a field, depending on the type of + * field it is and the type of justification used. The justification + * is only used on static single line fields, everything else will + * have the cursor_xpos set to 0. + */ +void +_formi_init_field_xpos(FIELD *field) +{ + /* not static or is multi-line which are not justified, so 0 it is */ + if (((field->opts & O_STATIC) != O_STATIC) || + ((field->rows + field->nrows) != 1)) { + field->cursor_xpos = 0; + return; + } + + switch (field->justification) { + case JUSTIFY_RIGHT: + field->cursor_xpos = field->cols - 1; + break; + + case JUSTIFY_CENTER: + field->cursor_xpos = (field->cols - 1) / 2; + break; + + default: /* assume left justify */ + field->cursor_xpos = 0; + break; + } +} + + +/* + * Open the debug file if it is not already open.... + */ +#ifdef DEBUG +int +_formi_create_dbg_file(void) +{ + if (dbg == NULL) { + dbg = fopen("___form_dbg.out", "w"); + if (dbg == NULL) { + fprintf(stderr, "Cannot open debug file!\n"); + return E_SYSTEM_ERROR; + } + } + + return E_OK; +} +#endif + +/* + * Check the sizing of the field, if the maximum size is set for a + * dynamic field then check that the number of rows or columns does + * not exceed the set maximum. The decision to check the rows or + * columns is made on the basis of how many rows are in the field - + * one row means the max applies to the number of columns otherwise it + * applies to the number of rows. If the row/column count is less + * than the maximum then return TRUE. + * + */ +static bool +check_field_size(FIELD *field) +{ + if ((field->opts & O_STATIC) != O_STATIC) { + /* dynamic field */ + if (field->max == 0) /* unlimited */ + return TRUE; + + if (field->rows == 1) { + return (field->alines->length < field->max); + } else { + return (field->row_count <= field->max); + } + } else { + if ((field->rows + field->nrows) == 1) { + return (field->alines->length <= field->cols); + } else { + return (field->row_count <= (field->rows + + field->nrows)); + } + } +} + +/* + * Set the form's current field to the first valid field on the page. + * Assume the fields have been sorted and stitched. + */ +int +_formi_pos_first_field(FORM *form) +{ + FIELD *cur; + int old_page; + + old_page = form->page; + + /* scan forward for an active page....*/ + while (form->page_starts[form->page].in_use == 0) { + form->page++; + if (form->page > form->max_page) { + form->page = old_page; + return E_REQUEST_DENIED; + } + } + + /* then scan for a field we can use */ + cur = form->fields[form->page_starts[form->page].first]; + while ((cur->opts & (O_VISIBLE | O_ACTIVE)) + != (O_VISIBLE | O_ACTIVE)) { + cur = CIRCLEQ_NEXT(cur, glue); + if (cur == (void *) &form->sorted_fields) { + form->page = old_page; + return E_REQUEST_DENIED; + } + } + + form->cur_field = cur->index; + return E_OK; +} + +/* + * Set the field to the next active and visible field, the fields are + * traversed in index order in the direction given. If the parameter + * use_sorted is TRUE then the sorted field list will be traversed instead + * of using the field index. + */ +int +_formi_pos_new_field(FORM *form, unsigned direction, unsigned use_sorted) +{ + FIELD *cur; + int i; + + i = form->cur_field; + cur = form->fields[i]; + + do { + if (direction == _FORMI_FORWARD) { + if (use_sorted == TRUE) { + if ((form->wrap == FALSE) && + (cur == CIRCLEQ_LAST(&form->sorted_fields))) + return E_REQUEST_DENIED; + cur = CIRCLEQ_NEXT(cur, glue); + i = cur->index; + } else { + if ((form->wrap == FALSE) && + ((i + 1) >= form->field_count)) + return E_REQUEST_DENIED; + i++; + if (i >= form->field_count) + i = 0; + } + } else { + if (use_sorted == TRUE) { + if ((form->wrap == FALSE) && + (cur == CIRCLEQ_FIRST(&form->sorted_fields))) + return E_REQUEST_DENIED; + cur = CIRCLEQ_PREV(cur, glue); + i = cur->index; + } else { + if ((form->wrap == FALSE) && (i <= 0)) + return E_REQUEST_DENIED; + i--; + if (i < 0) + i = form->field_count - 1; + } + } + + if ((form->fields[i]->opts & (O_VISIBLE | O_ACTIVE)) + == (O_VISIBLE | O_ACTIVE)) { + form->cur_field = i; + return E_OK; + } + } + while (i != form->cur_field); + + return E_REQUEST_DENIED; +} + +/* + * Destroy the list of line structs passed by freeing all allocated + * memory. + */ +static void +destroy_row_list(_FORMI_FIELD_LINES *start) +{ + _FORMI_FIELD_LINES *temp, *row; + _formi_tab_t *tt, *tp; + + row = start; + while (row != NULL) { + if (row->tabs != NULL) { + /* free up the tab linked list... */ + tp = row->tabs; + while (tp != NULL) { + tt = tp->fwd; + free(tp); + tp = tt; + } + } + + if (row->string != NULL) + free(row->string); + + temp = row->next; + free(row); + row = temp; + } +} + +/* + * Word wrap the contents of the field's buffer 0 if this is allowed. + * If the wrap is successful, that is, the row count nor the buffer + * size is exceeded then the function will return E_OK, otherwise it + * will return E_REQUEST_DENIED. + */ +int +_formi_wrap_field(FIELD *field, _FORMI_FIELD_LINES *loc) +{ + int width, wrap_err; + unsigned int pos, saved_xpos, saved_ypos, saved_cur_xpos; + unsigned int saved_row_count; + _FORMI_FIELD_LINES *saved_row, *row, *row_backup, *saved_cur_line; + _FORMI_FIELD_LINES *saved_start_line, *temp; + + if ((field->opts & O_STATIC) == O_STATIC) { + if ((field->rows + field->nrows) == 1) { + return E_OK; /* cannot wrap a single line */ + } + width = field->cols; + } else { + /* if we are limited to one line then don't try to wrap */ + if ((field->drows + field->nrows) == 1) { + return E_OK; + } + + /* + * hueristic - if a dynamic field has more than one line + * on the screen then the field grows rows, otherwise + * it grows columns, effectively a single line field. + * This is documented AT&T behaviour. + */ + if (field->rows > 1) { + width = field->cols; + } else { + return E_OK; + } + } + + row = loc; + + /* if we are not at the top of the field then back up one + * row because we may be able to merge the current row into + * the one above. + */ + if (row->prev != NULL) + row = row->prev; + + saved_row = row; + saved_xpos = field->row_xpos; + saved_cur_xpos = field->cursor_xpos; + saved_ypos = field->cursor_ypos; + saved_row_count = field->row_count; + + /* + * Save a copy of the lines affected, just in case things + * don't work out. + */ + if ((row_backup = copy_row(row)) == NULL) + return E_SYSTEM_ERROR; + + temp = row_backup; + row = row->next; + + saved_cur_line = temp; + saved_start_line = temp; + + while (row != NULL) { + if ((temp->next = copy_row(row)) == NULL) { + /* a row copy failed... free up allocations */ + destroy_row_list(row_backup); + return E_SYSTEM_ERROR; + } + + temp->next->prev = temp; + temp = temp->next; + + if (row == field->start_line) + saved_start_line = temp; + if (row == field->cur_line) + saved_cur_line = temp; + + row = row->next; + } + + row = saved_row; + while (row != NULL) { + pos = row->length - 1; + if (row->expanded < width) { + /* line may be too short, try joining some lines */ + if ((row->hard_ret == TRUE) && (row->next != NULL)) { + /* + * Skip the line if it has a hard return + * and it is not the last, we cannot join + * anything to it. + */ + row = row->next; + continue; + } + + if (row->next == NULL) { + /* + * If there are no more lines and this line + * is too short then our job is over. + */ + break; + } + + if (_formi_join_line(field, &row, + JOIN_NEXT_NW) == E_OK) { + continue; + } else + break; + } else if (row->expanded > width) { + /* line is too long, split it */ + + /* + * split on first whitespace before current word + * if the line has tabs we need to work out where + * the field border lies when the tabs are expanded. + */ + if (row->tabs == NULL) { + pos = width - 1; + if (pos >= row->expanded) + pos = row->expanded - 1; + } else { + pos = tab_fit_len(row, field->cols); + } + + if ((!isblank((unsigned char)row->string[pos])) && + ((field->opts & O_WRAP) == O_WRAP)) { + if (!isblank((unsigned char)row->string[pos - 1])) + pos = find_sow((unsigned int) pos, + &row); + /* + * If we cannot split the line then return + * NO_ROOM so the driver can tell that it + * should not autoskip (if that is enabled) + */ + if ((pos == 0) + || (!isblank((unsigned char)row->string[pos - 1]))) { + wrap_err = E_NO_ROOM; + goto restore_and_exit; + } + } + + /* if we are at the end of the string and it has + * a trailing blank, don't wrap the blank. + */ + if ((row->next == NULL) && (pos == row->length - 1) && + (isblank((unsigned char)row->string[pos])) && + row->expanded <= field->cols) + continue; + + /* + * otherwise, if we are still sitting on a + * blank but not at the end of the line + * move forward one char so the blank + * is on the line boundary. + */ + if ((isblank((unsigned char)row->string[pos])) && + (pos != row->length - 1)) + pos++; + + if (split_line(field, FALSE, pos, &row) != E_OK) { + wrap_err = E_REQUEST_DENIED; + goto restore_and_exit; + } + } else + /* line is exactly the right length, do next one */ + row = row->next; + } + + /* Check if we have not run out of room */ + if ((((field->opts & O_STATIC) == O_STATIC) && + field->row_count > (field->rows + field->nrows)) || + ((field->max != 0) && (field->row_count > field->max))) { + + wrap_err = E_REQUEST_DENIED; + + restore_and_exit: + if (saved_row->prev == NULL) { + field->alines = row_backup; + } else { + saved_row->prev->next = row_backup; + row_backup->prev = saved_row->prev; + } + + field->row_xpos = saved_xpos; + field->cursor_xpos = saved_cur_xpos; + field->cursor_ypos = saved_ypos; + field->row_count = saved_row_count; + field->start_line = saved_start_line; + field->cur_line = saved_cur_line; + + destroy_row_list(saved_row); + return wrap_err; + } + + destroy_row_list(row_backup); + return E_OK; +} + +/* + * Join the two lines that surround the location pos, the type + * variable indicates the direction of the join, JOIN_NEXT will join + * the next line to the current line, JOIN_PREV will join the current + * line to the previous line, the new lines will be wrapped unless the + * _NW versions of the directions are used. Returns E_OK if the join + * was successful or E_REQUEST_DENIED if the join cannot happen. + */ +static int +_formi_join_line(FIELD *field, _FORMI_FIELD_LINES **rowp, int direction) +{ + int old_len, count; + struct _formi_field_lines *saved; + char *newp; + _FORMI_FIELD_LINES *row = *rowp; +#ifdef DEBUG + int dbg_ok = FALSE; + + if (_formi_create_dbg_file() == E_OK) { + dbg_ok = TRUE; + } + + if (dbg_ok == TRUE) { + fprintf(dbg, "join_line: working on row %p, row_count = %d\n", + row, field->row_count); + } +#endif + + if ((direction == JOIN_NEXT) || (direction == JOIN_NEXT_NW)) { + /* + * See if there is another line following, or if the + * line contains a hard return then we don't join + * any lines to it. + */ + if ((row->next == NULL) || (row->hard_ret == TRUE)) { + return E_REQUEST_DENIED; + } + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, + "join_line: join_next before length = %d, expanded = %d", + row->length, row->expanded); + fprintf(dbg, + " :: next row length = %d, expanded = %d\n", + row->length, row->expanded); + } +#endif + + if (row->allocated < (row->length + row->next->length + 1)) { + if ((newp = realloc(row->string, (size_t)(row->length + + row->next->length + + 1))) == NULL) + return E_REQUEST_DENIED; + row->string = newp; + row->allocated = row->length + row->next->length + 1; + } + + strcat(row->string, row->next->string); + old_len = row->length; + row->length += row->next->length; + if (row->length > 0) + row->expanded = + _formi_tab_expanded_length(row->string, 0, + row->length - 1); + else + row->expanded = 0; + + _formi_calculate_tabs(row); + row->hard_ret = row->next->hard_ret; + + /* adjust current line if it is on the row being eaten */ + if (field->cur_line == row->next) { + field->cur_line = row; + field->row_xpos += old_len; + field->cursor_xpos = + _formi_tab_expanded_length(row->string, 0, + field->row_xpos); + if (field->cursor_xpos > 0) + field->cursor_xpos--; + + if (field->cursor_ypos > 0) + field->cursor_ypos--; + else { + if (field->start_line->prev != NULL) + field->start_line = + field->start_line->prev; + } + } + + /* remove joined line record from the row list */ + add_to_free(field, row->next); + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, + "join_line: exit length = %d, expanded = %d\n", + row->length, row->expanded); + } +#endif + } else { + if (row->prev == NULL) { + return E_REQUEST_DENIED; + } + + saved = row->prev; + + /* + * Don't try to join if the line above has a hard + * return on it. + */ + if (saved->hard_ret == TRUE) { + return E_REQUEST_DENIED; + } + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, + "join_line: join_prev before length = %d, expanded = %d", + row->length, row->expanded); + fprintf(dbg, + " :: prev row length = %d, expanded = %d\n", + saved->length, saved->expanded); + } +#endif + + if (saved->allocated < (row->length + saved->length + 1)) { + if ((newp = realloc(saved->string, + (size_t) (row->length + + saved->length + + 1))) == NULL) + return E_REQUEST_DENIED; + saved->string = newp; + saved->allocated = row->length + saved->length + 1; + } + + strcat(saved->string, row->string); + old_len = saved->length; + saved->length += row->length; + if (saved->length > 0) + saved->expanded = + _formi_tab_expanded_length(saved->string, 0, + saved->length - 1); + else + saved->length = 0; + + saved->hard_ret = row->hard_ret; + + /* adjust current line if it was on the row being eaten */ + if (field->cur_line == row) { + field->cur_line = saved; + field->row_xpos += old_len; + field->cursor_xpos = + _formi_tab_expanded_length(saved->string, 0, + field->row_xpos); + if (field->cursor_xpos > 0) + field->cursor_xpos--; + } + + add_to_free(field, row); + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, + "join_line: exit length = %d, expanded = %d\n", + saved->length, saved->expanded); + } +#endif + row = saved; + } + + + /* + * Work out where the line lies in the field in relation to + * the cursor_ypos. First count the rows from the start of + * the field until we hit the row we just worked on. + */ + saved = field->start_line; + count = 0; + while (saved->next != NULL) { + if (saved == row) + break; + count++; + saved = saved->next; + } + + /* now check if we need to adjust cursor_ypos */ + if (field->cursor_ypos > count) { + field->cursor_ypos--; + } + + field->row_count--; + *rowp = row; + + /* wrap the field if required, if this fails undo the change */ + if ((direction == JOIN_NEXT) || (direction == JOIN_PREV)) { + if (_formi_wrap_field(field, row) != E_OK) { + return E_REQUEST_DENIED; + } + } + + return E_OK; +} + +/* + * Split the line at the given position, if possible. If hard_split is + * TRUE then split the line regardless of the position, otherwise don't + * split at the beginning of a line. + */ +static int +split_line(FIELD *field, bool hard_split, unsigned pos, + _FORMI_FIELD_LINES **rowp) +{ + struct _formi_field_lines *new_line; + char *newp; + _FORMI_FIELD_LINES *row = *rowp; +#ifdef DEBUG + short dbg_ok = FALSE; +#endif + + /* if asked to split right where the line already starts then + * just return - nothing to do unless we are appending a line + * to the buffer. + */ + if ((pos == 0) && (hard_split == FALSE)) + return E_OK; + +#ifdef DEBUG + if (_formi_create_dbg_file() == E_OK) { + fprintf(dbg, "split_line: splitting line at %d\n", pos); + dbg_ok = TRUE; + } +#endif + + /* Need an extra line struct, check free list first */ + if (field->free != NULL) { + new_line = field->free; + field->free = new_line->next; + if (field->free != NULL) + field->free->prev = NULL; + } else { + if ((new_line = (struct _formi_field_lines *) + malloc(sizeof(struct _formi_field_lines))) == NULL) + return E_SYSTEM_ERROR; + new_line->prev = NULL; + new_line->next = NULL; + new_line->allocated = 0; + new_line->length = 0; + new_line->expanded = 0; + new_line->string = NULL; + new_line->hard_ret = FALSE; + new_line->tabs = NULL; + } + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, + "split_line: enter: length = %d, expanded = %d\n", + row->length, row->expanded); + } +#endif + + assert((row->length < INT_MAX) && (row->expanded < INT_MAX)); + + + /* add new line to the row list */ + new_line->next = row->next; + new_line->prev = row; + row->next = new_line; + if (new_line->next != NULL) + new_line->next->prev = new_line; + + new_line->length = row->length - pos; + if (new_line->length >= new_line->allocated) { + if ((newp = realloc(new_line->string, + (size_t) new_line->length + 1)) == NULL) + return E_SYSTEM_ERROR; + new_line->string = newp; + new_line->allocated = new_line->length + 1; + } + + strcpy(new_line->string, &row->string[pos]); + + row->length = pos; + row->string[pos] = '\0'; + + if (row->length != 0) + row->expanded = _formi_tab_expanded_length(row->string, 0, + row->length - 1); + else + row->expanded = 0; + _formi_calculate_tabs(row); + + if (new_line->length != 0) + new_line->expanded = + _formi_tab_expanded_length(new_line->string, 0, + new_line->length - 1); + else + new_line->expanded = 0; + + _formi_calculate_tabs(new_line); + + /* + * If the given row was the current line then adjust the + * current line pointer if necessary + */ + if ((field->cur_line == row) && (field->row_xpos >= pos)) { + field->cur_line = new_line; + field->row_xpos -= pos; + field->cursor_xpos = + _formi_tab_expanded_length(new_line->string, 0, + field->row_xpos); + if (field->cursor_xpos > 0) + field->cursor_xpos--; + + field->cursor_ypos++; + if (field->cursor_ypos >= field->rows) { + if (field->start_line->next != NULL) { + field->start_line = field->start_line->next; + field->cursor_ypos = field->rows - 1; + } + else + assert(field->start_line->next == NULL); + } + } + + /* + * If the line split had a hard return then replace the + * current line's hard return with a soft return and carry + * the hard return onto the line after. + */ + if (row->hard_ret == TRUE) { + new_line->hard_ret = TRUE; + row->hard_ret = FALSE; + } + + /* + * except where we are doing a hard split then the current + * row must have a hard return on it too... + */ + if (hard_split == TRUE) { + row->hard_ret = TRUE; + } + + assert(((row->expanded < INT_MAX) && + (new_line->expanded < INT_MAX) && + (row->length < INT_MAX) && + (new_line->length < INT_MAX))); + +#ifdef DEBUG + if (dbg_ok == TRUE) { + fprintf(dbg, "split_line: exit: "); + fprintf(dbg, "row.length = %d, row.expanded = %d, ", + row->length, row->expanded); + fprintf(dbg, + "next_line.length = %d, next_line.expanded = %d, ", + new_line->length, new_line->expanded); + fprintf(dbg, "row_count = %d\n", field->row_count + 1); + } +#endif + + field->row_count++; + *rowp = new_line; + + return E_OK; +} + +/* + * skip the blanks in the given string, start at the index start and + * continue forward until either the end of the string or a non-blank + * character is found. Return the index of either the end of the string or + * the first non-blank character. + */ +unsigned +_formi_skip_blanks(char *string, unsigned int start) +{ + unsigned int i; + + i = start; + + while ((string[i] != '\0') && isblank((unsigned char)string[i])) + i++; + + return i; +} + +/* + * Skip the blanks in the string associated with the given row, pass back + * the row and the offset at which the first non-blank is found. If no + * non-blank character is found then return the index to the last + * character on the last line. + */ + +unsigned +field_skip_blanks(unsigned int start, _FORMI_FIELD_LINES **rowp) +{ + unsigned int i; + _FORMI_FIELD_LINES *row, *last = NULL; + + row = *rowp; + i = start; + + do { + i = _formi_skip_blanks(&row->string[i], i); + if (!isblank((unsigned char)row->string[i])) { + last = row; + row = row->next; + /* + * don't reset if last line otherwise we will + * not be at the end of the string. + */ + if (row != NULL) + i = 0; + } else + break; + } + while (row != NULL); + + /* + * If we hit the end of the row list then point at the last row + * otherwise we return the row we found the blank on. + */ + if (row == NULL) + *rowp = last; + else + *rowp = row; + + return i; +} + +/* + * Return the index of the top left most field of the two given fields. + */ +static int +_formi_top_left(FORM *form, int a, int b) +{ + /* lower row numbers always win here.... */ + if (form->fields[a]->form_row < form->fields[b]->form_row) + return a; + + if (form->fields[a]->form_row > form->fields[b]->form_row) + return b; + + /* rows must be equal, check columns */ + if (form->fields[a]->form_col < form->fields[b]->form_col) + return a; + + if (form->fields[a]->form_col > form->fields[b]->form_col) + return b; + + /* if we get here fields must be in exactly the same place, punt */ + return a; +} + +/* + * Return the index to the field that is the bottom-right-most of the + * two given fields. + */ +static int +_formi_bottom_right(FORM *form, int a, int b) +{ + /* check the rows first, biggest row wins */ + if (form->fields[a]->form_row > form->fields[b]->form_row) + return a; + if (form->fields[a]->form_row < form->fields[b]->form_row) + return b; + + /* rows must be equal, check cols, biggest wins */ + if (form->fields[a]->form_col > form->fields[b]->form_col) + return a; + if (form->fields[a]->form_col < form->fields[b]->form_col) + return b; + + /* fields in the same place, punt */ + return a; +} + +/* + * Find the end of the current word in the string str, starting at + * offset - the end includes any trailing whitespace. If the end of + * the string is found before a new word then just return the offset + * to the end of the string. If do_join is TRUE then lines will be + * joined (without wrapping) until either the end of the field or the + * end of a word is found (whichever comes first). + */ +static int +find_eow(FIELD *cur, unsigned int offset, bool do_join, + _FORMI_FIELD_LINES **rowp) +{ + int start; + _FORMI_FIELD_LINES *row; + + row = *rowp; + start = offset; + + do { + /* first skip any non-whitespace */ + while ((row->string[start] != '\0') + && !isblank((unsigned char)row->string[start])) + start++; + + /* see if we hit the end of the string */ + if (row->string[start] == '\0') { + if (do_join == TRUE) { + if (row->next == NULL) + return start; + + if (_formi_join_line(cur, &row, JOIN_NEXT_NW) + != E_OK) + return E_REQUEST_DENIED; + } else { + do { + if (row->next == NULL) { + *rowp = row; + return start; + } else { + row = row->next; + start = 0; + } + } while (row->length == 0); + } + } + } while (!isblank((unsigned char)row->string[start])); + + do { + /* otherwise skip the whitespace.... */ + while ((row->string[start] != '\0') + && isblank((unsigned char)row->string[start])) + start++; + + if (row->string[start] == '\0') { + if (do_join == TRUE) { + if (row->next == NULL) + return start; + + if (_formi_join_line(cur, &row, JOIN_NEXT_NW) + != E_OK) + return E_REQUEST_DENIED; + } else { + do { + if (row->next == NULL) { + *rowp = row; + return start; + } else { + row = row->next; + start = 0; + } + } while (row->length == 0); + } + } + } while (isblank((unsigned char)row->string[start])); + + *rowp = row; + return start; +} + +/* + * Find the beginning of the current word in the string str, starting + * at offset. + */ +static int +find_sow(unsigned int offset, _FORMI_FIELD_LINES **rowp) +{ + int start; + char *str; + _FORMI_FIELD_LINES *row; + + row = *rowp; + str = row->string; + start = offset; + + do { + if (start > 0) { + if (isblank((unsigned char)str[start]) || + isblank((unsigned char)str[start - 1])) { + if (isblank((unsigned char)str[start - 1])) + start--; + /* skip the whitespace.... */ + while ((start >= 0) && + isblank((unsigned char)str[start])) + start--; + } + } + + /* see if we hit the start of the string */ + if (start < 0) { + do { + if (row->prev == NULL) { + *rowp = row; + start = 0; + return start; + } else { + row = row->prev; + str = row->string; + if (row->length > 0) + start = row->length - 1; + else + start = 0; + } + } while (row->length == 0); + } + } while (isblank((unsigned char)row->string[start])); + + /* see if we hit the start of the string */ + if (start < 0) { + *rowp = row; + return 0; + } + + /* now skip any non-whitespace */ + do { + while ((start >= 0) && !isblank((unsigned char)str[start])) + start--; + + + if (start < 0) { + do { + if (row->prev == NULL) { + *rowp = row; + start = 0; + return start; + } else { + row = row->prev; + str = row->string; + if (row->length > 0) + start = row->length - 1; + else + start = 0; + } + } while (row->length == 0); + } + } while (!isblank((unsigned char)str[start])); + + if (start > 0) { + start++; /* last loop has us pointing at a space, adjust */ + if (start >= row->length) { + if (row->next != NULL) { + start = 0; + row = row->next; + } else { + start = row->length - 1; + } + } + } + + if (start < 0) + start = 0; + + *rowp = row; + return start; +} + +/* + * Scroll the field forward the given number of lines. + */ +static void +_formi_scroll_fwd(FIELD *field, unsigned int amt) +{ + unsigned int count; + _FORMI_FIELD_LINES *end_row; + + end_row = field->start_line; + /* walk the line structs forward to find the bottom of the field */ + count = field->rows - 1; + while ((count > 0) && (end_row->next != NULL)) + { + count--; + end_row = end_row->next; + } + + /* check if there are lines to scroll */ + if ((count > 0) && (end_row->next == NULL)) + return; + + /* + * ok, lines to scroll - do this by walking both the start_line + * and the end_row at the same time for amt lines, we stop when + * either we have done the number of lines or end_row hits the + * last line in the field. + */ + count = amt; + while ((count > 0) && (end_row->next != NULL)) { + count--; + field->start_line = field->start_line->next; + end_row = end_row->next; + } +} + +/* + * Scroll the field backward the given number of lines. + */ +static void +_formi_scroll_back(FIELD *field, unsigned int amt) +{ + unsigned int count; + + /* check for lines above */ + if (field->start_line->prev == NULL) + return; + + /* + * Backward scroll is easy, follow row struct chain backward until + * the number of lines done or we reach the top of the field. + */ + count = amt; + while ((count > 0) && (field->start_line->prev != NULL)) { + count--; + field->start_line = field->start_line->prev; + } +} + +/* + * Scroll the field forward the given number of characters. + */ +void +_formi_hscroll_fwd(FIELD *field, _FORMI_FIELD_LINES *row, int unsigned amt) +{ + unsigned int end, scroll_amt, expanded; + _formi_tab_t *ts; + + + if ((row->tabs == NULL) || (row->tabs->in_use == FALSE)) { + /* if the line has no tabs things are easy... */ + end = field->start_char + field->cols + amt - 1; + scroll_amt = amt; + if (end > row->length) { + end = row->length; + scroll_amt = end - field->start_char - field->cols + 1; + } + } else { + /* + * If there are tabs we need to add on the scroll amount, + * find the last char position that will fit into + * the field and finally fix up the start_char. This + * is a lot of work but handling the case where there + * are not enough chars to scroll by amt is difficult. + */ + end = field->start_char + field->row_xpos + amt; + if (end >= row->length) + end = row->length - 1; + else { + expanded = _formi_tab_expanded_length( + row->string, + field->start_char + amt, + field->start_char + field->row_xpos + amt); + ts = row->tabs; + /* skip tabs to the lhs of our starting point */ + while ((ts != NULL) && (ts->in_use == TRUE) + && (ts->pos < end)) + ts = ts->fwd; + + while ((expanded <= field->cols) + && (end < row->length)) { + if (row->string[end] == '\t') { + assert((ts != NULL) + && (ts->in_use == TRUE)); + if (ts->pos == end) { + if ((expanded + ts->size) + > field->cols) + break; + expanded += ts->size; + ts = ts->fwd; + } + else + assert(ts->pos == end); + } else + expanded++; + end++; + } + } + + scroll_amt = tab_fit_window(field, end, field->cols); + if (scroll_amt < field->start_char) + scroll_amt = 1; + else + scroll_amt -= field->start_char; + + scroll_amt = min(scroll_amt, amt); + } + + field->start_char += scroll_amt; + field->cursor_xpos = + _formi_tab_expanded_length(row->string, + field->start_char, + field->row_xpos + + field->start_char) - 1; + +} + +/* + * Scroll the field backward the given number of characters. + */ +void +_formi_hscroll_back(FIELD *field, _FORMI_FIELD_LINES *row, unsigned int amt) +{ + field->start_char -= min(field->start_char, amt); + field->cursor_xpos = + _formi_tab_expanded_length(row->string, field->start_char, + field->row_xpos + + field->start_char) - 1; + if (field->cursor_xpos >= field->cols) { + field->row_xpos = 0; + field->cursor_xpos = 0; + } +} + +/* + * Find the different pages in the form fields and assign the form + * page_starts array with the information to find them. + */ +int +_formi_find_pages(FORM *form) +{ + int i, cur_page = 0; + + if ((form->page_starts = (_FORMI_PAGE_START *) + malloc((form->max_page + 1) * sizeof(_FORMI_PAGE_START))) == NULL) + return E_SYSTEM_ERROR; + + /* initialise the page starts array */ + memset(form->page_starts, 0, + (form->max_page + 1) * sizeof(_FORMI_PAGE_START)); + + for (i =0; i < form->field_count; i++) { + if (form->fields[i]->page_break == 1) + cur_page++; + if (form->page_starts[cur_page].in_use == 0) { + form->page_starts[cur_page].in_use = 1; + form->page_starts[cur_page].first = i; + form->page_starts[cur_page].last = i; + form->page_starts[cur_page].top_left = i; + form->page_starts[cur_page].bottom_right = i; + } else { + form->page_starts[cur_page].last = i; + form->page_starts[cur_page].top_left = + _formi_top_left(form, + form->page_starts[cur_page].top_left, + i); + form->page_starts[cur_page].bottom_right = + _formi_bottom_right(form, + form->page_starts[cur_page].bottom_right, + i); + } + } + + return E_OK; +} + +/* + * Completely redraw the field of the given form. + */ +void +_formi_redraw_field(FORM *form, int field) +{ + unsigned int pre, post, flen, slen, i, j, start, line; + unsigned int tab, cpos, len; + char *str, c; + FIELD *cur; + _FORMI_FIELD_LINES *row; +#ifdef DEBUG + char buffer[100]; +#endif + + cur = form->fields[field]; + flen = cur->cols; + slen = 0; + start = 0; + line = 0; + + for (row = cur->start_line; ((row != NULL) && (line < cur->rows)); + row = row->next, line++) { + wmove(form->scrwin, (int) (cur->form_row + line), + (int) cur->form_col); + if ((cur->rows + cur->nrows) == 1) { + if ((cur->cols + cur->start_char) >= row->length) + len = row->length; + else + len = cur->cols + cur->start_char; + if (row->string != NULL) + slen = _formi_tab_expanded_length( + row->string, cur->start_char, len); + else + slen = 0; + + if (slen > cur->cols) + slen = cur->cols; + slen += cur->start_char; + } else + slen = row->expanded; + + if ((cur->opts & O_STATIC) == O_STATIC) { + switch (cur->justification) { + case JUSTIFY_RIGHT: + post = 0; + if (flen < slen) + pre = 0; + else + pre = flen - slen; + break; + + case JUSTIFY_CENTER: + if (flen < slen) { + pre = 0; + post = 0; + } else { + pre = flen - slen; + post = pre = pre / 2; + /* get padding right if + centring is not even */ + if ((post + pre + slen) < flen) + post++; + } + break; + + case NO_JUSTIFICATION: + case JUSTIFY_LEFT: + default: + pre = 0; + if (flen <= slen) + post = 0; + else { + post = flen - slen; + if (post > flen) + post = flen; + } + break; + } + } else { + /* dynamic fields are not justified */ + pre = 0; + if (flen <= slen) + post = 0; + else { + post = flen - slen; + if (post > flen) + post = flen; + } + + /* but they do scroll.... */ + + if (pre > cur->start_char - start) + pre = pre - cur->start_char + start; + else + pre = 0; + + if (slen > cur->start_char) { + slen -= cur->start_char; + if (slen > flen) + post = 0; + else + post = flen - slen; + + if (post > flen) + post = flen; + } else { + slen = 0; + post = flen - pre; + } + } + + if (form->cur_field == field) + wattrset(form->scrwin, cur->fore); + else + wattrset(form->scrwin, cur->back); + + str = &row->string[cur->start_char]; + +#ifdef DEBUG + if (_formi_create_dbg_file() == E_OK) { + fprintf(dbg, + "redraw_field: start=%d, pre=%d, slen=%d, flen=%d, post=%d, start_char=%d\n", + start, pre, slen, flen, post, cur->start_char); + if (str != NULL) { + if (row->expanded != 0) { + strncpy(buffer, str, flen); + } else { + strcpy(buffer, "(empty)"); + } + } else { + strcpy(buffer, "(null)"); + } + buffer[flen] = '\0'; + fprintf(dbg, "redraw_field: %s\n", buffer); + } +#endif + + for (i = start + cur->start_char; i < pre; i++) + waddch(form->scrwin, cur->pad); + +#ifdef DEBUG + fprintf(dbg, "redraw_field: will add %d chars\n", + min(slen, flen)); +#endif + for (i = 0, cpos = cur->start_char; i < min(slen, flen); + i++, str++, cpos++) + { + c = *str; + tab = 0; /* just to shut gcc up */ +#ifdef DEBUG + fprintf(dbg, "adding char str[%d]=%c\n", + cpos + cur->start_char, c); +#endif + if (((cur->opts & O_PUBLIC) != O_PUBLIC)) { + if (c == '\t') + tab = add_tab(form, row, cpos, + cur->pad); + else + waddch(form->scrwin, cur->pad); + } else if ((cur->opts & O_VISIBLE) == O_VISIBLE) { + if (c == '\t') + tab = add_tab(form, row, cpos, ' '); + else + waddch(form->scrwin, c); + } else { + if (c == '\t') + tab = add_tab(form, row, cpos, ' '); + else + waddch(form->scrwin, ' '); + } + + /* + * If we have had a tab then skip forward + * the requisite number of chars to keep + * things in sync. + */ + if (c == '\t') + i += tab - 1; + } + + for (i = 0; i < post; i++) + waddch(form->scrwin, cur->pad); + } + + for (i = line; i < cur->rows; i++) { + wmove(form->scrwin, (int) (cur->form_row + i), + (int) cur->form_col); + + if (form->cur_field == field) + wattrset(form->scrwin, cur->fore); + else + wattrset(form->scrwin, cur->back); + + for (j = 0; j < cur->cols; j++) { + waddch(form->scrwin, cur->pad); + } + } + + wattrset(form->scrwin, cur->back); + return; +} + +/* + * Add the correct number of the given character to simulate a tab + * in the field. + */ +static int +add_tab(FORM *form, _FORMI_FIELD_LINES *row, unsigned int i, char c) +{ + int j; + _formi_tab_t *ts = row->tabs; + + while ((ts != NULL) && (ts->pos != i)) + ts = ts->fwd; + + assert(ts != NULL); + + for (j = 0; j < ts->size; j++) + waddch(form->scrwin, c); + + return ts->size; +} + + +/* + * Display the fields attached to the form that are on the current page + * on the screen. + * + */ +int +_formi_draw_page(FORM *form) +{ + int i; + + if (form->page_starts[form->page].in_use == 0) + return E_BAD_ARGUMENT; + + wclear(form->scrwin); + + for (i = form->page_starts[form->page].first; + i <= form->page_starts[form->page].last; i++) + _formi_redraw_field(form, i); + + return E_OK; +} + +/* + * Add the character c at the position pos in buffer 0 of the given field + */ +int +_formi_add_char(FIELD *field, unsigned int pos, char c) +{ + char *new, old_c; + unsigned int new_size; + int status; + _FORMI_FIELD_LINES *row, *temp, *next_temp; + + row = field->cur_line; + + /* + * If buffer has not had a string before, set it to a blank + * string. Everything should flow from there.... + */ + if (row->string == NULL) { + if ((row->string = (char *) malloc((size_t)INITIAL_LINE_ALLOC)) + == NULL) + return E_SYSTEM_ERROR; + row->string[0] = '\0'; + row->allocated = INITIAL_LINE_ALLOC; + row->length = 0; + row->expanded = 0; + } + + if (_formi_validate_char(field, c) != E_OK) { +#ifdef DEBUG + fprintf(dbg, "add_char: char %c failed char validation\n", c); +#endif + return E_INVALID_FIELD; + } + + if ((c == '\t') && (field->cols <= 8)) { +#ifdef DEBUG + fprintf(dbg, "add_char: field too small for a tab\n"); +#endif + return E_NO_ROOM; + } + +#ifdef DEBUG + fprintf(dbg, "add_char: pos=%d, char=%c\n", pos, c); + fprintf(dbg, "add_char enter: xpos=%d, row_pos=%d, start=%d\n", + field->cursor_xpos, field->row_xpos, field->start_char); + fprintf(dbg, "add_char enter: length=%d(%d), allocated=%d\n", + row->expanded, row->length, row->allocated); + fprintf(dbg, "add_char enter: %s\n", row->string); + fprintf(dbg, "add_char enter: buf0_status=%d\n", field->buf0_status); +#endif + if (((field->opts & O_BLANK) == O_BLANK) && + (field->buf0_status == FALSE) && + ((field->row_xpos + field->start_char) == 0)) { + row = field->alines; + if (row->next != NULL) { + /* shift all but one line structs to free list */ + temp = row->next; + do { + next_temp = temp->next; + add_to_free(field, temp); + temp = next_temp; + } while (temp != NULL); + } + + row->length = 0; + row->string[0] = '\0'; + pos = 0; + field->start_char = 0; + field->start_line = row; + field->cur_line = row; + field->row_count = 1; + field->row_xpos = 0; + field->cursor_ypos = 0; + row->expanded = 0; + row->length = 0; + _formi_init_field_xpos(field); + } + + + if ((field->overlay == 0) + || ((field->overlay == 1) && (pos >= row->length))) { + /* first check if the field can have more chars...*/ + if (check_field_size(field) == FALSE) + return E_REQUEST_DENIED; + + if (row->length + 2 + >= row->allocated) { + new_size = row->allocated + 16 - (row->allocated % 16); + if ((new = (char *) realloc(row->string, + (size_t) new_size )) == NULL) + return E_SYSTEM_ERROR; + row->allocated = new_size; + row->string = new; + } + } + + if ((field->overlay == 0) && (row->length > pos)) { + bcopy(&row->string[pos], &row->string[pos + 1], + (size_t) (row->length - pos + 1)); + } + + old_c = row->string[pos]; + row->string[pos] = c; + if (pos >= row->length) { + /* make sure the string is terminated if we are at the + * end of the string, the terminator would be missing + * if we are are at the end of the field. + */ + row->string[pos + 1] = '\0'; + } + + /* only increment the length if we are inserting characters + * OR if we are at the end of the field in overlay mode. + */ + if ((field->overlay == 0) + || ((field->overlay == 1) && (pos >= row->length))) { + row->length++; + } + + _formi_calculate_tabs(row); + row->expanded = _formi_tab_expanded_length(row->string, 0, + row->length - 1); + + /* wrap the field, if needed */ + status = _formi_wrap_field(field, row); + + row = field->cur_line; + pos = field->row_xpos; + + /* + * check the wrap worked or that we have not exceeded the + * max field size - this can happen if the field is re-wrapped + * and the row count is increased past the set limit. + */ + if ((status != E_OK) || (check_field_size(field) == FALSE)) { + if ((field->overlay == 0) + || ((field->overlay == 1) + && (pos >= (row->length - 1) /*XXXX- append check???*/))) { + /* + * wrap failed for some reason, back out the + * char insert + */ + bcopy(&row->string[pos + 1], &row->string[pos], + (size_t) (row->length - pos)); + row->length--; + if (pos > 0) + pos--; + } else if (field->overlay == 1) { + /* back out character overlay */ + row->string[pos] = old_c; + } + + _formi_calculate_tabs(row); + + _formi_wrap_field(field, row); + /* + * If we are here then either the status is bad or we + * simply ran out of room. If the status is E_OK then + * we ran out of room, let the form driver know this. + */ + if (status == E_OK) + status = E_REQUEST_DENIED; + + } else { + field->buf0_status = TRUE; + field->row_xpos++; + if ((field->rows + field->nrows) == 1) { + status = _formi_set_cursor_xpos(field, FALSE); + } else { + field->cursor_xpos = + _formi_tab_expanded_length( + row->string, 0, field->row_xpos - 1); + + /* + * Annoying corner case - if we are right in + * the bottom right corner of the field we + * need to scroll the field one line so the + * cursor is positioned correctly in the + * field. + */ + if ((field->cursor_xpos >= field->cols) && + (field->cursor_ypos == (field->rows - 1))) { + field->cursor_ypos--; + field->start_line = field->start_line->next; + } + } + } + + assert((field->cursor_xpos <= field->cols) + && (field->cursor_ypos < 400000)); + +#ifdef DEBUG + fprintf(dbg, "add_char exit: xpos=%d, row_pos=%d, start=%d\n", + field->cursor_xpos, field->row_xpos, field->start_char); + fprintf(dbg, "add_char_exit: length=%d(%d), allocated=%d\n", + row->expanded, row->length, row->allocated); + fprintf(dbg, "add_char exit: ypos=%d, start_line=%p\n", + field->cursor_ypos, field->start_line); + fprintf(dbg,"add_char exit: %s\n", row->string); + fprintf(dbg, "add_char exit: buf0_status=%d\n", field->buf0_status); + fprintf(dbg, "add_char exit: status = %s\n", + (status == E_OK)? "OK" : "FAILED"); +#endif + return status; +} + +/* + * Set the position of the cursor on the screen in the row depending on + * where the current position in the string is and the justification + * that is to be applied to the field. Justification is only applied + * to single row, static fields. + */ +static int +_formi_set_cursor_xpos(FIELD *field, int noscroll) +{ + int just, pos; + + just = field->justification; + pos = field->start_char + field->row_xpos; + +#ifdef DEBUG + fprintf(dbg, + "cursor_xpos enter: pos %d, start_char %d, row_xpos %d, xpos %d\n", + pos, field->start_char, field->row_xpos, field->cursor_xpos); +#endif + + /* + * make sure we apply the correct justification to non-static + * fields. + */ + if (((field->rows + field->nrows) != 1) || + ((field->opts & O_STATIC) != O_STATIC)) + just = JUSTIFY_LEFT; + + switch (just) { + case JUSTIFY_RIGHT: + field->cursor_xpos = field->cols - 1 + - _formi_tab_expanded_length( + field->cur_line->string, 0, + field->cur_line->length - 1) + + _formi_tab_expanded_length( + field->cur_line->string, 0, + field->row_xpos); + break; + + case JUSTIFY_CENTER: + field->cursor_xpos = ((field->cols - 1) + - _formi_tab_expanded_length( + field->cur_line->string, 0, + field->cur_line->length - 1) + 1) / 2 + + _formi_tab_expanded_length(field->cur_line->string, + 0, field->row_xpos); + + if (field->cursor_xpos > (field->cols - 1)) + field->cursor_xpos = (field->cols - 1); + break; + + default: + field->cursor_xpos = _formi_tab_expanded_length( + field->cur_line->string, + field->start_char, + field->row_xpos + field->start_char); + if ((field->cursor_xpos <= (field->cols - 1)) && + ((field->start_char + field->row_xpos) + < field->cur_line->length)) + field->cursor_xpos--; + + if (field->cursor_xpos > (field->cols - 1)) { + if ((field->opts & O_STATIC) == O_STATIC) { + field->start_char = 0; + + if (field->row_xpos + == (field->cur_line->length - 1)) { + field->cursor_xpos = field->cols - 1; + } else { + field->cursor_xpos = + _formi_tab_expanded_length( + field->cur_line->string, + field->start_char, + field->row_xpos + + field->start_char + - 1) - 1; + } + } else { + if (noscroll == FALSE) { + field->start_char = + tab_fit_window( + field, + field->start_char + + field->row_xpos, + field->cols); + field->row_xpos = pos + - field->start_char; + field->cursor_xpos = + _formi_tab_expanded_length( + field->cur_line->string, + field->start_char, + field->row_xpos + + field->start_char - 1); + } else { + field->cursor_xpos = (field->cols - 1); + } + } + + } + break; + } + +#ifdef DEBUG + fprintf(dbg, + "cursor_xpos exit: pos %d, start_char %d, row_xpos %d, xpos %d\n", + pos, field->start_char, field->row_xpos, field->cursor_xpos); +#endif + return E_OK; +} + +/* + * Manipulate the text in a field, this takes the given form and performs + * the passed driver command on the current text field. Returns 1 if the + * text field was modified. + */ +int +_formi_manipulate_field(FORM *form, int c) +{ + FIELD *cur; + char *str, saved; + unsigned int start, end, pos, status, old_count, size; + unsigned int old_xpos, old_row_pos; + int len, wb; + bool eat_char; + _FORMI_FIELD_LINES *row, *rs; + + cur = form->fields[form->cur_field]; + if (cur->cur_line->string == NULL) + return E_REQUEST_DENIED; + +#ifdef DEBUG + fprintf(dbg, "entry: request is REQ_%s\n", reqs[c - REQ_MIN_REQUEST]); + fprintf(dbg, + "entry: xpos=%d, row_pos=%d, start_char=%d, length=%d, allocated=%d\n", + cur->cursor_xpos, cur->row_xpos, cur->start_char, + cur->cur_line->length, cur->cur_line->allocated); + fprintf(dbg, "entry: start_line=%p, ypos=%d\n", cur->start_line, + cur->cursor_ypos); + fprintf(dbg, "entry: string="); + if (cur->cur_line->string == NULL) + fprintf(dbg, "(null)\n"); + else + fprintf(dbg, "\"%s\"\n", cur->cur_line->string); +#endif + + /* Cannot manipulate a null string! */ + if (cur->cur_line->string == NULL) + return E_REQUEST_DENIED; + + saved = '\0'; + row = cur->cur_line; + + switch (c) { + case REQ_RIGHT_CHAR: + /* + * The right_char request performs the same function + * as the next_char request except that the cursor is + * not wrapped if it is at the end of the line, so + * check if the cursor is at the end of the line and + * deny the request otherwise just fall through to + * the next_char request handler. + */ + if (cur->cursor_xpos >= cur->cols - 1) + return E_REQUEST_DENIED; + + /* FALLTHRU */ + + case REQ_NEXT_CHAR: + /* for a dynamic field allow an offset of one more + * char so we can insert chars after end of string. + * Static fields cannot do this so deny request if + * cursor is at the end of the field. + */ + if (((cur->opts & O_STATIC) == O_STATIC) && + (cur->row_xpos == cur->cols - 1) && + ((cur->rows + cur->nrows) == 1)) + return E_REQUEST_DENIED; + + if (((cur->rows + cur->nrows) == 1) && + (cur->row_xpos + cur->start_char + 1) > row->length) + return E_REQUEST_DENIED; + + if ((cur->rows + cur->nrows) == 1) { + cur->row_xpos++; + _formi_set_cursor_xpos(cur, (c == REQ_RIGHT_CHAR)); + } else { + if (cur->cursor_xpos >= (row->expanded - 1)) { + if ((row->next == NULL) || + (c == REQ_RIGHT_CHAR)) + return E_REQUEST_DENIED; + + cur->cursor_xpos = 0; + cur->row_xpos = 0; + cur->cur_line = cur->cur_line->next; + if (cur->cursor_ypos == (cur->rows - 1)) + cur->start_line = + cur->start_line->next; + else + cur->cursor_ypos++; + } else { + old_xpos = cur->cursor_xpos; + old_row_pos = cur->row_xpos; + if (row->string[cur->row_xpos] == '\t') + cur->cursor_xpos += tab_size(row, + cur->row_xpos); + else + cur->cursor_xpos++; + cur->row_xpos++; + if (cur->cursor_xpos + >= row->expanded) { + if ((row->next == NULL) || + (c == REQ_RIGHT_CHAR)) { + cur->cursor_xpos = old_xpos; + cur->row_xpos = old_row_pos; + return E_REQUEST_DENIED; + } + + cur->cursor_xpos = 0; + cur->row_xpos = 0; + cur->cur_line = cur->cur_line->next; + if (cur->cursor_ypos + == (cur->rows - 1)) + cur->start_line = + cur->start_line->next; + else + cur->cursor_ypos++; + } + } + } + + break; + + case REQ_LEFT_CHAR: + /* + * The behaviour of left_char is the same as prev_char + * except that the cursor will not wrap if it has + * reached the LHS of the field, so just check this + * and fall through if we are not at the LHS. + */ + if (cur->cursor_xpos == 0) + return E_REQUEST_DENIED; + + /* FALLTHRU */ + case REQ_PREV_CHAR: + if ((cur->rows + cur->nrows) == 1) { + if (cur->row_xpos == 0) { + if (cur->start_char > 0) + cur->start_char--; + else + return E_REQUEST_DENIED; + } else { + cur->row_xpos--; + _formi_set_cursor_xpos(cur, FALSE); + } + } else { + if ((cur->cursor_xpos == 0) && + (cur->cursor_ypos == 0) && + (cur->start_line->prev == NULL)) + return E_REQUEST_DENIED; + + pos = cur->row_xpos; + if (cur->cursor_xpos > 0) { + if (row->string[pos] == '\t') { + size = tab_size(row, pos); + if (size > cur->cursor_xpos) { + cur->cursor_xpos = 0; + cur->row_xpos = 0; + } else { + cur->row_xpos--; + cur->cursor_xpos -= size; + } + } else { + cur->cursor_xpos--; + cur->row_xpos--; + } + } else { + cur->cur_line = cur->cur_line->prev; + if (cur->cursor_ypos > 0) + cur->cursor_ypos--; + else + cur->start_line = + cur->start_line->prev; + row = cur->cur_line; + if (row->expanded > 0) { + cur->cursor_xpos = row->expanded - 1; + } else { + cur->cursor_xpos = 0; + } + + if (row->length > 0) + cur->row_xpos = row->length - 1; + else + cur->row_xpos = 0; + } + } + + break; + + case REQ_DOWN_CHAR: + /* + * The down_char request has the same functionality as + * the next_line request excepting that the field is not + * scrolled if the cursor is at the bottom of the field. + * Check to see if the cursor is at the bottom of the field + * and if it is then deny the request otherwise fall + * through to the next_line handler. + */ + if (cur->cursor_ypos >= cur->rows - 1) + return E_REQUEST_DENIED; + + /* FALLTHRU */ + + case REQ_NEXT_LINE: + if ((row->next == NULL) || (cur->cur_line->next == NULL)) + return E_REQUEST_DENIED; + + cur->cur_line = cur->cur_line->next; + if ((cur->cursor_ypos + 1) >= cur->rows) { + cur->start_line = cur->start_line->next; + } else + cur->cursor_ypos++; + row = cur->cur_line; + + if (row->length == 0) { + cur->row_xpos = 0; + cur->cursor_xpos = 0; + } else { + if (cur->cursor_xpos > (row->expanded - 1)) + cur->cursor_xpos = row->expanded - 1; + + cur->row_xpos = tab_fit_len(row, cur->cursor_xpos + 1); + if (cur->row_xpos == 0) + cur->cursor_xpos = 0; + else + cur->cursor_xpos = + _formi_tab_expanded_length( + row->string, 0, cur->row_xpos); + if (cur->cursor_xpos > 0) + cur->cursor_xpos--; + } + break; + + case REQ_UP_CHAR: + /* + * The up_char request has the same functionality as + * the prev_line request excepting the field is not + * scrolled, check if the cursor is at the top of the + * field, if it is deny the request otherwise fall + * through to the prev_line handler. + */ + if (cur->cursor_ypos == 0) + return E_REQUEST_DENIED; + + /* FALLTHRU */ + + case REQ_PREV_LINE: + if (cur->cur_line->prev == NULL) + return E_REQUEST_DENIED; + + if (cur->cursor_ypos == 0) { + if (cur->start_line->prev == NULL) + return E_REQUEST_DENIED; + cur->start_line = cur->start_line->prev; + } else + cur->cursor_ypos--; + + cur->cur_line = cur->cur_line->prev; + row = cur->cur_line; + + if (row->length == 0) { + cur->row_xpos = 0; + cur->cursor_xpos = 0; + } else { + if (cur->cursor_xpos > (row->expanded - 1)) + cur->cursor_xpos = row->expanded - 1; + + cur->row_xpos = tab_fit_len(row, cur->cursor_xpos + 1); + cur->cursor_xpos = + _formi_tab_expanded_length(row->string, + 0, cur->row_xpos); + if (cur->cursor_xpos > 0) + cur->cursor_xpos--; + } + break; + + case REQ_NEXT_WORD: + start = cur->row_xpos + cur->start_char; + str = row->string; + + wb = find_eow(cur, start, FALSE, &row); + if (wb < 0) + return wb; + + start = wb; + /* check if we hit the end */ + if (str[start] == '\0') + return E_REQUEST_DENIED; + + /* otherwise we must have found the start of a word...*/ + if ((cur->rows + cur->nrows) == 1) { + /* single line field */ + size = _formi_tab_expanded_length(str, + cur->start_char, start); + if (size < cur->cols) { + cur->row_xpos = start - cur->start_char; + } else { + cur->start_char = start; + cur->row_xpos = 0; + } + _formi_set_cursor_xpos(cur, FALSE); + } else { + /* multiline field */ + cur->cur_line = row; + adjust_ypos(cur, row); + + cur->row_xpos = start; + cur->cursor_xpos = + _formi_tab_expanded_length( + row->string, 0, cur->row_xpos) - 1; + } + break; + + case REQ_PREV_WORD: + start = cur->start_char + cur->row_xpos; + if (cur->start_char > 0) + start--; + + if ((start == 0) && (row->prev == NULL)) + return E_REQUEST_DENIED; + + if (start == 0) { + row = row->prev; + if (row->length > 0) + start = row->length - 1; + else + start = 0; + } + + str = row->string; + + start = find_sow(start, &row); + + if ((cur->rows + cur->nrows) == 1) { + /* single line field */ + size = _formi_tab_expanded_length(str, + cur->start_char, start); + + if (start > cur->start_char) { + cur->row_xpos = start - cur->start_char; + } else { + cur->start_char = start; + cur->row_xpos = 0; + } + _formi_set_cursor_xpos(cur, FALSE); + } else { + /* multiline field */ + cur->cur_line = row; + adjust_ypos(cur, row); + cur->row_xpos = start; + cur->cursor_xpos = + _formi_tab_expanded_length( + row->string, 0, + cur->row_xpos) - 1; + } + + break; + + case REQ_BEG_FIELD: + cur->start_char = 0; + while (cur->start_line->prev != NULL) + cur->start_line = cur->start_line->prev; + cur->cur_line = cur->start_line; + cur->row_xpos = 0; + _formi_init_field_xpos(cur); + cur->cursor_ypos = 0; + break; + + case REQ_BEG_LINE: + cur->row_xpos = 0; + _formi_init_field_xpos(cur); + cur->start_char = 0; + break; + + case REQ_END_FIELD: + while (cur->cur_line->next != NULL) + cur->cur_line = cur->cur_line->next; + + if (cur->row_count > cur->rows) { + cur->start_line = cur->cur_line; + pos = cur->rows - 1; + while (pos > 0) { + cur->start_line = cur->start_line->prev; + pos--; + } + cur->cursor_ypos = cur->rows - 1; + } else { + cur->cursor_ypos = cur->row_count - 1; + } + + /* we fall through here deliberately, we are on the + * correct row, now we need to get to the end of the + * line. + */ + /* FALLTHRU */ + + case REQ_END_LINE: + row = cur->cur_line; + + if ((cur->rows + cur->nrows) == 1) { + if (row->expanded > cur->cols - 1) { + if ((cur->opts & O_STATIC) != O_STATIC) { + cur->start_char = tab_fit_window( + cur, row->length, + cur->cols) + 1; + cur->row_xpos = row->length + - cur->start_char; + } else { + cur->start_char = 0; + cur->row_xpos = cur->cols - 1; + } + } else { + cur->row_xpos = row->length + 1; + cur->start_char = 0; + } + _formi_set_cursor_xpos(cur, FALSE); + } else { + cur->row_xpos = row->length - 1; + cur->cursor_xpos = row->expanded - 1; + if (row->next == NULL) { + cur->row_xpos++; + cur->cursor_xpos++; + } + } + break; + + case REQ_NEW_LINE: + start = cur->start_char + cur->row_xpos; + if ((status = split_line(cur, TRUE, start, &row)) != E_OK) + return status; + cur->cur_line->hard_ret = TRUE; + cur->cursor_xpos = 0; + cur->row_xpos = 0; + break; + + case REQ_INS_CHAR: + if ((status = _formi_add_char(cur, cur->start_char + + cur->row_xpos, + cur->pad)) != E_OK) + return status; + break; + + case REQ_INS_LINE: + if ((status = split_line(cur, TRUE, 0, &row)) != E_OK) + return status; + cur->cur_line->hard_ret = TRUE; + break; + + case REQ_DEL_CHAR: + row = cur->cur_line; + start = cur->start_char + cur->row_xpos; + end = row->length - 1; + if ((start >= row->length) && (row->next == NULL)) + return E_REQUEST_DENIED; + + if ((start == row->length - 1) || (row->length == 0)) { + if ((cur->rows + cur->nrows) > 1) { + /* + * Firstly, check if the current line has + * a hard return. In this case we just + * want to "delete" the hard return and + * re-wrap the field. The hard return + * does not occupy a character space in + * the buffer but we must make it appear + * like it does for a deletion. + */ + if (row->hard_ret == TRUE) { + row->hard_ret = FALSE; + if (_formi_join_line(cur, &row, + JOIN_NEXT) + != E_OK) { + row->hard_ret = TRUE; + return 0; + } else { + return 1; + } + } + + /* + * If we have more than one row, join the + * next row to make things easier unless + * we are at the end of the string, in + * that case the join would fail but we + * really want to delete the last char + * in the field. + */ + if (row->next != NULL) { + if (_formi_join_line(cur, &row, + JOIN_NEXT_NW) + != E_OK) { + return E_REQUEST_DENIED; + } + } + } + } + + saved = row->string[start]; + bcopy(&row->string[start + 1], &row->string[start], + (size_t) (end - start + 1)); + row->string[end] = '\0'; + row->length--; + if (row->length > 0) + row->expanded = _formi_tab_expanded_length( + row->string, 0, row->length - 1); + else + row->expanded = 0; + + /* + * recalculate tabs for a single line field, multiline + * fields will do this when the field is wrapped. + */ + if ((cur->rows + cur->nrows) == 1) + _formi_calculate_tabs(row); + /* + * if we are at the end of the string then back the + * cursor pos up one to stick on the end of the line + */ + if (start == row->length) { + if (row->length > 1) { + if ((cur->rows + cur->nrows) == 1) { + pos = cur->row_xpos + cur->start_char; + cur->start_char = + tab_fit_window( + cur, + cur->start_char + cur->row_xpos, + cur->cols); + cur->row_xpos = pos - cur->start_char + - 1; + _formi_set_cursor_xpos(cur, FALSE); + } else { + if (cur->row_xpos == 0) { + if (row->next != NULL) { + if (_formi_join_line( + cur, &row, + JOIN_PREV_NW) + != E_OK) { + return E_REQUEST_DENIED; + } + } else { + if (cur->row_count > 1) + cur->row_count--; + } + + } + + cur->row_xpos = start - 1; + cur->cursor_xpos = + _formi_tab_expanded_length( + row->string, + 0, cur->row_xpos - 1); + if ((cur->cursor_xpos > 0) + && (start != (row->expanded - 1))) + cur->cursor_xpos--; + } + + start--; + } else { + start = 0; + cur->row_xpos = 0; + _formi_init_field_xpos(cur); + } + } + + if ((cur->rows + cur->nrows) > 1) { + if (_formi_wrap_field(cur, row) != E_OK) { + bcopy(&row->string[start], + &row->string[start + 1], + (size_t) (end - start)); + row->length++; + row->string[start] = saved; + _formi_wrap_field(cur, row); + return E_REQUEST_DENIED; + } + } + break; + + case REQ_DEL_PREV: + if ((cur->cursor_xpos == 0) && (cur->start_char == 0) + && (cur->start_line->prev == NULL) + && (cur->cursor_ypos == 0)) + return E_REQUEST_DENIED; + + row = cur->cur_line; + start = cur->row_xpos + cur->start_char; + end = row->length - 1; + eat_char = TRUE; + + if ((cur->start_char + cur->row_xpos) == 0) { + if (row->prev == NULL) + return E_REQUEST_DENIED; + + /* + * If we are a multiline field then check if + * the line above has a hard return. If it does + * then just "eat" the hard return and re-wrap + * the field. + */ + if (row->prev->hard_ret == TRUE) { + row->prev->hard_ret = FALSE; + if (_formi_join_line(cur, &row, + JOIN_PREV) != E_OK) { + row->prev->hard_ret = TRUE; + return 0; + } + + eat_char = FALSE; + } else { + start = row->prev->length; + /* + * Join this line to the previous + * one. + */ + if (_formi_join_line(cur, &row, + JOIN_PREV_NW) != E_OK) { + return 0; + } + end = row->length - 1; + } + } + + if (eat_char == TRUE) { + /* + * eat a char from the buffer. Normally we do + * this unless we have deleted a "hard return" + * in which case we just want to join the lines + * without losing a char. + */ + saved = row->string[start - 1]; + bcopy(&row->string[start], &row->string[start - 1], + (size_t) (end - start + 1)); + row->length--; + row->string[row->length] = '\0'; + row->expanded = _formi_tab_expanded_length( + row->string, 0, row->length - 1); + } + + if ((cur->rows + cur->nrows) == 1) { + _formi_calculate_tabs(row); + pos = cur->row_xpos + cur->start_char; + if (pos > 0) + pos--; + cur->start_char = + tab_fit_window(cur, + cur->start_char + cur->row_xpos, + cur->cols); + cur->row_xpos = pos - cur->start_char; + _formi_set_cursor_xpos(cur, FALSE); + } else { + if (eat_char == TRUE) { + cur->row_xpos--; + if (cur->row_xpos > 0) + cur->cursor_xpos = + _formi_tab_expanded_length( + row->string, 0, + cur->row_xpos - 1); + else + cur->cursor_xpos = 0; + } + + if ((_formi_wrap_field(cur, row) != E_OK)) { + bcopy(&row->string[start - 1], + &row->string[start], + (size_t) (end - start)); + row->length++; + row->string[start - 1] = saved; + row->string[row->length] = '\0'; + _formi_wrap_field(cur, row); + return E_REQUEST_DENIED; + } + } + break; + + case REQ_DEL_LINE: + if (((cur->rows + cur->nrows) == 1) || + (cur->row_count == 1)) { + /* single line case */ + row->length = 0; + row->expanded = row->length = 0; + cur->row_xpos = 0; + _formi_init_field_xpos(cur); + cur->cursor_ypos = 0; + } else { + /* multiline field */ + old_count = cur->row_count; + cur->row_count--; + if (cur->row_count == 0) + cur->row_count = 1; + + if (old_count == 1) { + row->expanded = row->length = 0; + cur->cursor_xpos = 0; + cur->row_xpos = 0; + cur->cursor_ypos = 0; + } else + add_to_free(cur, row); + + if (row->next == NULL) { + if (cur->cursor_ypos == 0) { + if (cur->start_line->prev != NULL) { + cur->start_line = + cur->start_line->prev; + } + } else { + cur->cursor_ypos--; + } + } + + if (old_count > 1) { + if (cur->cursor_xpos > row->expanded) { + cur->cursor_xpos = row->expanded - 1; + cur->row_xpos = row->length - 1; + } + + cur->start_line = cur->alines; + rs = cur->start_line; + cur->cursor_ypos = 0; + while (rs != row) { + if (cur->cursor_ypos < cur->rows) + cur->cursor_ypos++; + else + cur->start_line = + cur->start_line->next; + rs = rs->next; + } + } + } + break; + + case REQ_DEL_WORD: + start = cur->start_char + cur->row_xpos; + str = row->string; + + wb = find_eow(cur, start, TRUE, &row); + if (wb < 0) + return wb; + + end = wb; + + /* + * If not at the start of a word then find the start, + * we cannot blindly call find_sow because this will + * skip back a word if we are already at the start of + * a word. + */ + if ((start > 0) + && !(isblank((unsigned char)str[start - 1]) && + !isblank((unsigned char)str[start]))) + start = find_sow(start, &row); + str = row->string; + /* XXXX hmmmm what if start and end on diff rows? XXXX */ + bcopy(&str[end], &str[start], + (size_t) (row->length - end + 1)); + len = end - start; + row->length -= len; + + if ((cur->rows + cur->nrows) > 1) { + row = cur->start_line + cur->cursor_ypos; + if (row->next != NULL) { + /* + * if not on the last row we need to + * join on the next row so the line + * will be re-wrapped. + */ + _formi_join_line(cur, &row, JOIN_NEXT_NW); + } + _formi_wrap_field(cur, row); + cur->row_xpos = start; + cur->cursor_xpos = _formi_tab_expanded_length( + row->string, 0, cur->row_xpos); + if (cur->cursor_xpos > 0) + cur->cursor_xpos--; + } else { + _formi_calculate_tabs(row); + cur->row_xpos = start - cur->start_char; + if (cur->row_xpos > 0) + cur->row_xpos--; + _formi_set_cursor_xpos(cur, FALSE); + } + break; + + case REQ_CLR_EOL: + row->string[cur->row_xpos + 1] = '\0'; + row->length = cur->row_xpos + 1; + row->expanded = cur->cursor_xpos + 1; + break; + + case REQ_CLR_EOF: + row = cur->cur_line->next; + while (row != NULL) { + rs = row->next; + add_to_free(cur, row); + row = rs; + cur->row_count--; + } + break; + + case REQ_CLR_FIELD: + row = cur->alines->next; + cur->cur_line = cur->alines; + cur->start_line = cur->alines; + + while (row != NULL) { + rs = row->next; + add_to_free(cur, row); + row = rs; + } + + cur->alines->string[0] = '\0'; + cur->alines->length = 0; + cur->alines->expanded = 0; + cur->row_count = 1; + cur->cursor_ypos = 0; + cur->row_xpos = 0; + _formi_init_field_xpos(cur); + cur->start_char = 0; + break; + + case REQ_OVL_MODE: + cur->overlay = 1; + break; + + case REQ_INS_MODE: + cur->overlay = 0; + break; + + case REQ_SCR_FLINE: + _formi_scroll_fwd(cur, 1); + break; + + case REQ_SCR_BLINE: + _formi_scroll_back(cur, 1); + break; + + case REQ_SCR_FPAGE: + _formi_scroll_fwd(cur, cur->rows); + break; + + case REQ_SCR_BPAGE: + _formi_scroll_back(cur, cur->rows); + break; + + case REQ_SCR_FHPAGE: + _formi_scroll_fwd(cur, cur->rows / 2); + break; + + case REQ_SCR_BHPAGE: + _formi_scroll_back(cur, cur->rows / 2); + break; + + case REQ_SCR_FCHAR: + _formi_hscroll_fwd(cur, row, 1); + break; + + case REQ_SCR_BCHAR: + _formi_hscroll_back(cur, row, 1); + break; + + case REQ_SCR_HFLINE: + _formi_hscroll_fwd(cur, row, cur->cols); + break; + + case REQ_SCR_HBLINE: + _formi_hscroll_back(cur, row, cur->cols); + break; + + case REQ_SCR_HFHALF: + _formi_hscroll_fwd(cur, row, cur->cols / 2); + break; + + case REQ_SCR_HBHALF: + _formi_hscroll_back(cur, row, cur->cols / 2); + break; + + default: + return 0; + } + +#ifdef DEBUG + fprintf(dbg, + "exit: cursor_xpos=%d, row_xpos=%d, start_char=%d, length=%d, allocated=%d\n", + cur->cursor_xpos, cur->row_xpos, cur->start_char, + cur->cur_line->length, cur->cur_line->allocated); + fprintf(dbg, "exit: start_line=%p, ypos=%d\n", cur->start_line, + cur->cursor_ypos); + fprintf(dbg, "exit: string=\"%s\"\n", cur->cur_line->string); + assert ((cur->cursor_xpos < INT_MAX) && (cur->row_xpos < INT_MAX) + && (cur->cursor_xpos >= cur->row_xpos)); +#endif + return 1; +} + +/* + * Validate the give character by passing it to any type character + * checking routines, if they exist. + */ +int +_formi_validate_char(FIELD *field, char c) +{ + int ret_val; + + if (field->type == NULL) + return E_OK; + + ret_val = E_INVALID_FIELD; + _formi_do_char_validation(field, field->type, c, &ret_val); + + return ret_val; +} + + +/* + * Perform the validation of the character, invoke all field_type validation + * routines. If the field is ok then update ret_val to E_OK otherwise + * ret_val is not changed. + */ +static void +_formi_do_char_validation(FIELD *field, FIELDTYPE *type, char c, int *ret_val) +{ + if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) { + _formi_do_char_validation(field, type->link->next, c, ret_val); + _formi_do_char_validation(field, type->link->prev, c, ret_val); + } else { + if (type->char_check == NULL) + *ret_val = E_OK; + else { + if (type->char_check((int)(unsigned char) c, + field->args) == TRUE) + *ret_val = E_OK; + } + } +} + +/* + * Validate the current field. If the field validation returns success then + * return E_OK otherwise return E_INVALID_FIELD. + * + */ +int +_formi_validate_field(FORM *form) +{ + FIELD *cur; + int ret_val, count; + + + if ((form == NULL) || (form->fields == NULL) || + (form->fields[0] == NULL)) + return E_INVALID_FIELD; + + cur = form->fields[form->cur_field]; + + /* + * Sync the buffer if it has been modified so the field + * validation routines can use it and because this is + * the correct behaviour according to AT&T implementation. + */ + if ((cur->buf0_status == TRUE) + && ((ret_val = _formi_sync_buffer(cur)) != E_OK)) + return ret_val; + + /* + * If buffer is untouched then the string pointer may be + * NULL, see if this is ok or not. + */ + if (cur->buffers[0].string == NULL) { + if ((cur->opts & O_NULLOK) == O_NULLOK) + return E_OK; + else + return E_INVALID_FIELD; + } + + count = _formi_skip_blanks(cur->buffers[0].string, 0); + + /* check if we have a null field, depending on the nullok flag + * this may be acceptable or not.... + */ + if (cur->buffers[0].string[count] == '\0') { + if ((cur->opts & O_NULLOK) == O_NULLOK) + return E_OK; + else + return E_INVALID_FIELD; + } + + /* check if an unmodified field is ok */ + if (cur->buf0_status == 0) { + if ((cur->opts & O_PASSOK) == O_PASSOK) + return E_OK; + else + return E_INVALID_FIELD; + } + + /* if there is no type then just accept the field */ + if (cur->type == NULL) + return E_OK; + + ret_val = E_INVALID_FIELD; + _formi_do_validation(cur, cur->type, &ret_val); + + return ret_val; +} + +/* + * Perform the validation of the field, invoke all field_type validation + * routines. If the field is ok then update ret_val to E_OK otherwise + * ret_val is not changed. + */ +static void +_formi_do_validation(FIELD *field, FIELDTYPE *type, int *ret_val) +{ + if ((type->flags & _TYPE_IS_LINKED) == _TYPE_IS_LINKED) { + _formi_do_validation(field, type->link->next, ret_val); + _formi_do_validation(field, type->link->prev, ret_val); + } else { + if (type->field_check == NULL) + *ret_val = E_OK; + else { + if (type->field_check(field, field_buffer(field, 0)) + == TRUE) + *ret_val = E_OK; + } + } +} + +/* + * Select the next/previous choice for the field, the driver command + * selecting the direction will be passed in c. Return 1 if a choice + * selection succeeded, 0 otherwise. + */ +int +_formi_field_choice(FORM *form, int c) +{ + FIELDTYPE *type; + FIELD *field; + + if ((form == NULL) || (form->fields == NULL) || + (form->fields[0] == NULL) || + (form->fields[form->cur_field]->type == NULL)) + return 0; + + field = form->fields[form->cur_field]; + type = field->type; + + switch (c) { + case REQ_NEXT_CHOICE: + if (type->next_choice == NULL) + return 0; + else + return type->next_choice(field, + field_buffer(field, 0)); + + case REQ_PREV_CHOICE: + if (type->prev_choice == NULL) + return 0; + else + return type->prev_choice(field, + field_buffer(field, 0)); + + default: /* should never happen! */ + return 0; + } +} + +/* + * Update the fields if they have changed. The parameter old has the + * previous current field as the current field may have been updated by + * the driver. Return 1 if the form page needs updating. + * + */ +int +_formi_update_field(FORM *form, int old_field) +{ + int cur, i; + + cur = form->cur_field; + + if (old_field != cur) { + if (!((cur >= form->page_starts[form->page].first) && + (cur <= form->page_starts[form->page].last))) { + /* not on same page any more */ + for (i = 0; i < form->max_page; i++) { + if ((form->page_starts[i].in_use == 1) && + (form->page_starts[i].first <= cur) && + (form->page_starts[i].last >= cur)) { + form->page = i; + return 1; + } + } + } + } + + _formi_redraw_field(form, old_field); + _formi_redraw_field(form, form->cur_field); + return 0; +} + +/* + * Compare function for the field sorting + * + */ +static int +field_sort_compare(const void *one, const void *two) +{ + const FIELD *a, *b; + int tl; + + /* LINTED const castaway; we don't modify these! */ + a = (const FIELD *) *((const FIELD **) one); + b = (const FIELD *) *((const FIELD **) two); + + if (a == NULL) + return 1; + + if (b == NULL) + return -1; + + /* + * First check the page, we want the fields sorted by page. + * + */ + if (a->page != b->page) + return ((a->page > b->page)? 1 : -1); + + tl = _formi_top_left(a->parent, a->index, b->index); + + /* + * sort fields left to right, top to bottom so the top left is + * the lesser value.... + */ + return ((tl == a->index)? -1 : 1); +} + +/* + * Sort the fields in a form ready for driver traversal. + */ +void +_formi_sort_fields(FORM *form) +{ + FIELD **sort_area; + int i; + + CIRCLEQ_INIT(&form->sorted_fields); + + if ((sort_area = (FIELD **) malloc(sizeof(FIELD *) * form->field_count)) + == NULL) + return; + + bcopy(form->fields, sort_area, + (size_t) (sizeof(FIELD *) * form->field_count)); + qsort(sort_area, (size_t) form->field_count, sizeof(FIELD *), + field_sort_compare); + + for (i = 0; i < form->field_count; i++) + CIRCLEQ_INSERT_TAIL(&form->sorted_fields, sort_area[i], glue); + + free(sort_area); +} + +/* + * Set the neighbours for all the fields in the given form. + */ +void +_formi_stitch_fields(FORM *form) +{ + int above_row, below_row, end_above, end_below, cur_row, real_end; + FIELD *cur, *above, *below; + + /* + * check if the sorted fields circle queue is empty, just + * return if it is. + */ + if (CIRCLEQ_EMPTY(&form->sorted_fields)) + return; + + /* initially nothing is above..... */ + above_row = -1; + end_above = TRUE; + above = NULL; + + /* set up the first field as the current... */ + cur = CIRCLEQ_FIRST(&form->sorted_fields); + cur_row = cur->form_row; + + /* find the first field on the next row if any */ + below = CIRCLEQ_NEXT(cur, glue); + below_row = -1; + end_below = TRUE; + real_end = TRUE; + while (below != (void *)&form->sorted_fields) { + if (below->form_row != cur_row) { + below_row = below->form_row; + end_below = FALSE; + real_end = FALSE; + break; + } + below = CIRCLEQ_NEXT(below, glue); + } + + /* walk the sorted fields, setting the neighbour pointers */ + while (cur != (void *) &form->sorted_fields) { + if (cur == CIRCLEQ_FIRST(&form->sorted_fields)) + cur->left = NULL; + else + cur->left = CIRCLEQ_PREV(cur, glue); + + if (cur == CIRCLEQ_LAST(&form->sorted_fields)) + cur->right = NULL; + else + cur->right = CIRCLEQ_NEXT(cur, glue); + + if (end_above == TRUE) + cur->up = NULL; + else { + cur->up = above; + above = CIRCLEQ_NEXT(above, glue); + if (above_row != above->form_row) { + end_above = TRUE; + above_row = above->form_row; + } + } + + if (end_below == TRUE) + cur->down = NULL; + else { + cur->down = below; + below = CIRCLEQ_NEXT(below, glue); + if (below == (void *) &form->sorted_fields) { + end_below = TRUE; + real_end = TRUE; + } else if (below_row != below->form_row) { + end_below = TRUE; + below_row = below->form_row; + } + } + + cur = CIRCLEQ_NEXT(cur, glue); + if ((cur != (void *) &form->sorted_fields) + && (cur_row != cur->form_row)) { + cur_row = cur->form_row; + if (end_above == FALSE) { + for (; above != CIRCLEQ_FIRST(&form->sorted_fields); + above = CIRCLEQ_NEXT(above, glue)) { + if (above->form_row != above_row) { + above_row = above->form_row; + break; + } + } + } else if (above == NULL) { + above = CIRCLEQ_FIRST(&form->sorted_fields); + end_above = FALSE; + above_row = above->form_row; + } else + end_above = FALSE; + + if (end_below == FALSE) { + while (below_row == below->form_row) { + below = CIRCLEQ_NEXT(below, + glue); + if (below == + (void *)&form->sorted_fields) { + real_end = TRUE; + end_below = TRUE; + break; + } + } + + if (below != (void *)&form->sorted_fields) + below_row = below->form_row; + } else if (real_end == FALSE) + end_below = FALSE; + + } + } +} + +/* + * Calculate the length of the displayed line allowing for any tab + * characters that need to be expanded. We assume that the tab stops + * are 8 characters apart. The parameters start and end are the + * character positions in the string str we want to get the length of, + * the function returns the number of characters from the start + * position to the end position that should be displayed after any + * intervening tabs have been expanded. + */ +int +_formi_tab_expanded_length(char *str, unsigned int start, unsigned int end) +{ + int len, start_len, i; + + /* if we have a null string then there is no length */ + if (str[0] == '\0') + return 0; + + len = 0; + start_len = 0; + + /* + * preceding tabs affect the length tabs in the span, so + * we need to calculate the length including the stuff before + * start and then subtract off the unwanted bit. + */ + for (i = 0; i <= end; i++) { + if (i == start) /* stash preamble length for later */ + start_len = len; + + if (str[i] == '\0') + break; + + if (str[i] == '\t') + len = len - (len % 8) + 8; + else + len++; + } + +#ifdef DEBUG + if (dbg != NULL) { + fprintf(dbg, + "tab_expanded: start=%d, end=%d, expanded=%d (diff=%d)\n", + start, end, (len - start_len), (end - start)); + } +#endif + + return (len - start_len); +} + +/* + * Calculate the tab stops on a given line in the field and set up + * the tabs list with the results. We do this by scanning the line for tab + * characters and if one is found, noting the position and the number of + * characters to get to the next tab stop. This information is kept to + * make manipulating the field (scrolling and so on) easier to handle. + */ +void +_formi_calculate_tabs(_FORMI_FIELD_LINES *row) +{ + _formi_tab_t *ts = row->tabs, *old_ts = NULL, **tsp; + int i, j; + + /* + * If the line already has tabs then invalidate them by + * walking the list and killing the in_use flag. + */ + for (; ts != NULL; ts = ts->fwd) + ts->in_use = FALSE; + + + /* + * Now look for tabs in the row and record the info... + */ + tsp = &row->tabs; + for (i = 0, j = 0; i < row->length; i++, j++) { + if (row->string[i] == '\t') { + if (*tsp == NULL) { + if ((*tsp = (_formi_tab_t *) + malloc(sizeof(_formi_tab_t))) == NULL) + return; + (*tsp)->back = old_ts; + (*tsp)->fwd = NULL; + } + + (*tsp)->in_use = TRUE; + (*tsp)->pos = i; + (*tsp)->size = 8 - (j % 8); + j += (*tsp)->size - 1; + old_ts = *tsp; + tsp = &(*tsp)->fwd; + } + } +} + +/* + * Return the size of the tab padding for a tab character at the given + * position. Return 1 if there is not a tab char entry matching the + * given location. + */ +static int +tab_size(_FORMI_FIELD_LINES *row, unsigned int i) +{ + _formi_tab_t *ts; + + ts = row->tabs; + while ((ts != NULL) && (ts->pos != i)) + ts = ts->fwd; + + if (ts == NULL) + return 1; + else + return ts->size; +} + +/* + * Find the character offset that corresponds to longest tab expanded + * string that will fit into the given window. Walk the string backwards + * evaluating the sizes of any tabs that are in the string. Note that + * using this function on a multi-line window will produce undefined + * results - it is really only required for a single row field. + */ +static int +tab_fit_window(FIELD *field, unsigned int pos, unsigned int window) +{ + int scroll_amt, i; + _formi_tab_t *ts; + + /* first find the last tab */ + ts = field->alines->tabs; + + /* + * unless there are no tabs - just return the window size, + * if there is enough room, otherwise 0. + */ + if (ts == NULL) { + if (field->alines->length < window) + return 0; + else + return field->alines->length - window + 1; + } + + while ((ts->fwd != NULL) && (ts->fwd->in_use == TRUE)) + ts = ts->fwd; + + /* + * now walk backwards finding the first tab that is to the + * left of our starting pos. + */ + while ((ts != NULL) && (ts->in_use == TRUE) && (ts->pos > pos)) + ts = ts->back; + + scroll_amt = 0; + for (i = pos; i >= 0; i--) { + if (field->alines->string[i] == '\t') { + assert((ts != NULL) && (ts->in_use == TRUE)); + if (ts->pos == i) { + if ((scroll_amt + ts->size) > window) { + break; + } + scroll_amt += ts->size; + ts = ts->back; + } + else + assert(ts->pos == i); + } else { + scroll_amt++; + if (scroll_amt > window) + break; + } + } + + return ++i; +} + +/* + * Return the position of the last character that will fit into the + * given width after tabs have been expanded for a given row of a given + * field. + */ +static unsigned int +tab_fit_len(_FORMI_FIELD_LINES *row, unsigned int width) +{ + unsigned int pos, len, row_pos; + _formi_tab_t *ts; + + ts = row->tabs; + pos = 0; + len = 0; + row_pos = 0; + + if (width == 0) + return 0; + + while ((len < width) && (pos < row->length)) { + if (row->string[pos] == '\t') { + assert((ts != NULL) && (ts->in_use == TRUE)); + if (ts->pos == row_pos) { + if ((len + ts->size) > width) + break; + len += ts->size; + ts = ts->fwd; + } + else + assert(ts->pos == row_pos); + } else + len++; + pos++; + row_pos++; + } + + if (pos > 0) + pos--; + return pos; +} + +/* + * Sync the field line structures with the contents of buffer 0 for that + * field. We do this by walking all the line structures and concatenating + * all the strings into one single string in buffer 0. + */ +int +_formi_sync_buffer(FIELD *field) +{ + _FORMI_FIELD_LINES *line; + char *nstr, *tmp; + unsigned length; + + if (field->alines == NULL) + return E_BAD_ARGUMENT; + + if (field->alines->string == NULL) + return E_BAD_ARGUMENT; + + /* + * init nstr up front, just in case there are no line contents, + * this could happen if the field just contains hard returns. + */ + if ((nstr = malloc(sizeof(char))) == NULL) + return E_SYSTEM_ERROR; + nstr[0] = '\0'; + + line = field->alines; + length = 1; /* allow for terminating null */ + + while (line != NULL) { + if (line->length != 0) { + if ((tmp = realloc(nstr, + (size_t) (length + line->length))) + == NULL) { + if (nstr != NULL) + free(nstr); + return (E_SYSTEM_ERROR); + } + + nstr = tmp; + strcat(nstr, line->string); + length += line->length; + } + + line = line->next; + } + + if (field->buffers[0].string != NULL) + free(field->buffers[0].string); + field->buffers[0].allocated = length; + field->buffers[0].length = length - 1; + field->buffers[0].string = nstr; + return E_OK; +} + + + diff --git a/lib/libform/internals.h b/lib/libform/internals.h new file mode 100644 index 000000000..52c8ae427 --- /dev/null +++ b/lib/libform/internals.h @@ -0,0 +1,151 @@ +/* $NetBSD: internals.h,v 1.10 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +#include "form.h" + +#ifndef FORMI_INTERNALS_H +#define FORMI_INTERNALS_H 1 + +#ifdef DEBUG +extern FILE *dbg; +#endif + +/* direction definitions for _formi_pos_new_field */ +#define _FORMI_BACKWARD 1 +#define _FORMI_FORWARD 2 + +/* define the default options for a form... */ +#define DEFAULT_FORM_OPTS (O_VISIBLE | O_ACTIVE | O_PUBLIC | O_EDIT | \ + O_WRAP | O_BLANK | O_AUTOSKIP | O_NULLOK | \ + O_PASSOK | O_STATIC) + +/* definitions of the flags for the FIELDTYPE structure */ +#define _TYPE_NO_FLAGS 0 +#define _TYPE_HAS_ARGS 0x01 +#define _TYPE_IS_LINKED 0x02 +#define _TYPE_IS_BUILTIN 0x04 +#define _TYPE_HAS_CHOICE 0x08 + +typedef struct formi_type_link_struct formi_type_link; + +struct formi_type_link_struct +{ + FIELDTYPE *next; + FIELDTYPE *prev; +}; + + +struct _formi_page_struct +{ + int in_use; + int first; + int last; + int top_left; + int bottom_right; +}; + +struct _formi_tab_stops +{ + struct _formi_tab_stops *fwd; + struct _formi_tab_stops *back; + unsigned char in_use; + unsigned pos; + unsigned size; +}; + +typedef struct _formi_tab_stops _formi_tab_t; + +/* lines structure for the field - keeps start and ends and length of the + * lines in a field. + */ +struct _formi_field_lines +{ + _FORMI_FIELD_LINES *prev; + _FORMI_FIELD_LINES *next; + unsigned allocated; + unsigned length; + unsigned expanded; + char *string; + unsigned char hard_ret; /* line contains hard return */ + _formi_tab_t *tabs; +}; + + +/* function prototypes */ +unsigned +_formi_skip_blanks(char *string, unsigned int start); +int +_formi_add_char(FIELD *cur, unsigned pos, char c); +void +_formi_calculate_tabs(_FORMI_FIELD_LINES *row); +int +_formi_draw_page(FORM *form); +int +_formi_find_pages(FORM *form); +int +_formi_field_choice(FORM *form, int c); +void +_formi_init_field_xpos(FIELD *field); +int +_formi_manipulate_field(FORM *form, int c); +int +_formi_pos_first_field(FORM *form); +int +_formi_pos_new_field(FORM *form, unsigned direction, unsigned use_sorted); +void +_formi_redraw_field(FORM *form, int field); +void +_formi_sort_fields(FORM *form); +void +_formi_stitch_fields(FORM *form); +int +_formi_tab_expanded_length(char *str, unsigned int start, unsigned int end); +int +_formi_update_field(FORM *form, int old_field); +int +_formi_validate_char(FIELD *field, char c); +int +_formi_validate_field(FORM *form); +int +_formi_wrap_field(FIELD *field, _FORMI_FIELD_LINES *pos); +int +_formi_sync_buffer(FIELD *field); + +#ifdef DEBUG +int +_formi_create_dbg_file(void); +#endif /* DEBUG */ + +#endif + + + diff --git a/lib/libform/post.c b/lib/libform/post.c new file mode 100644 index 000000000..7fe4085e3 --- /dev/null +++ b/lib/libform/post.c @@ -0,0 +1,119 @@ +/* $NetBSD: post.c,v 1.9 2003/03/09 00:57:19 lukem Exp $ */ + +/*- + * Copyright (c) 1998-2000 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: post.c,v 1.9 2003/03/09 00:57:19 lukem Exp $"); + +#include "form.h" +#include "internals.h" + +/* + * Post the form to the screen. + */ +int +post_form(FORM *form) +{ + int rows, cols, status; + + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->posted == 1) + return E_POSTED; + + if ((form->fields == NULL) || (form->fields[0] == NULL)) + return E_NOT_CONNECTED; + + if (form->in_init == 1) + return E_BAD_STATE; + + if (scale_form(form, &rows, &cols) != E_OK) + return E_SYSTEM_ERROR; + + if ((form->scrwin != NULL) && ((rows > getmaxy(form->scrwin)) + || (cols > getmaxx(form->scrwin)))) { + return E_NO_ROOM; + } + +#ifdef DEBUG + if (_formi_create_dbg_file() != E_OK) + return E_SYSTEM_ERROR; +#endif + + form->in_init = 1; + if (form->form_init != NULL) + form->form_init(form); + + if (form->field_init != NULL) + form->field_init(form); + form->in_init = 0; + + _formi_pos_first_field(form); + if ((status = _formi_draw_page(form)) != E_OK) + return status; + + form->posted = 1; + pos_form_cursor(form); + + return E_OK; +} + +/* + * Unpost the form from the screen + */ +int +unpost_form(FORM *form) +{ + + if (form == NULL) + return E_BAD_ARGUMENT; + + if (form->posted != 1) + return E_NOT_POSTED; + + if (form->in_init == 1) + return E_BAD_STATE; + + form->in_init = 1; + if (form->field_term != NULL) + form->field_term(form); + + if (form->form_term != NULL) + form->form_term(form); + form->in_init = 0; + + wclear(form->scrwin); + + form->posted = 0; + + return E_OK; +} + diff --git a/lib/libform/shlib_version b/lib/libform/shlib_version new file mode 100644 index 000000000..8890efa58 --- /dev/null +++ b/lib/libform/shlib_version @@ -0,0 +1,5 @@ +# $NetBSD: shlib_version,v 1.17 2009/01/11 03:07:48 christos Exp $ +# Remember to update distrib/sets/lists/base/shl.* when changing +# +major=6 +minor=0 diff --git a/lib/libform/std_header.c b/lib/libform/std_header.c new file mode 100644 index 000000000..26ff3e3a7 --- /dev/null +++ b/lib/libform/std_header.c @@ -0,0 +1,34 @@ +/* $NetBSD: std_header.c,v 1.3 2003/03/09 00:57:19 lukem Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: std_header.c,v 1.3 2003/03/09 00:57:19 lukem Exp $"); + diff --git a/lib/libform/type_alnum.c b/lib/libform/type_alnum.c new file mode 100644 index 000000000..14bc6546f --- /dev/null +++ b/lib/libform/type_alnum.c @@ -0,0 +1,176 @@ +/* $NetBSD: type_alnum.c,v 1.10 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The alpha-numeric type handling. + */ + +typedef struct +{ + unsigned width; +} alnum_args; + +/* + * Create the alnum arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_alnum_args(va_list *args) +{ + alnum_args *new; + + new = (alnum_args *) malloc(sizeof(alnum_args)); + + if (new != NULL) + new->width = va_arg(*args, int); + + return (void *) new; +} + +/* + * Copy the alnum argument structure. + */ +static char * +copy_alnum_args(char *args) +{ + alnum_args *new; + + new = (alnum_args *) malloc(sizeof(alnum_args)); + + if (new != NULL) + new->width = ((alnum_args *) (void *)args)->width; + + return (char *) (void *) new; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_alnum_args(char *args) +{ + if (args != NULL) + free(args); +} + +/* + * Check the contents of the field buffer are alphanumeric only. + */ +static int +alnum_check_field(FIELD *field, char *args) +{ + int width, start, cur, end; + char *buf, *new; + + width = ((alnum_args *) (void *) field->args)->width; + buf = args; + start = 0; + + if (buf == NULL) + return FALSE; + + /* skip leading white space */ + while ((buf[start] != '\0') + && ((buf[start] == ' ') || (buf[start] == '\t'))) + start++; + + /* no good if we have hit the end */ + if (buf[start] == '\0') + return FALSE; + + /* find the end of the non-whitespace stuff */ + cur = start; + while(isalnum((unsigned char)buf[cur])) + cur++; + + /* no good if it exceeds the width */ + if ((cur - start) > width) + return FALSE; + + end = cur; + + /* check there is only trailing whitespace */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we are not at the end of the string */ + if (buf[cur] != '\0') + return FALSE; + + if ((new = (char *) malloc(sizeof(char) * (end - start))) == NULL) + return FALSE; + + if ((end - start) >= 1) { + strncpy(new, &buf[start], (size_t) (end - start - 1)); + new[end] = '\0'; + } else + new[0]= '\0'; + + set_field_buffer(field, 0, new); + free(new); + + /* otherwise all was ok */ + return TRUE; +} + +/* + * Check the given character is alpha-numeric, return TRUE if it is. + */ +static int +alnum_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return (isalnum(c) ? TRUE : FALSE); +} + +static FIELDTYPE builtin_alnum = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_alnum_args, /* make_args */ + copy_alnum_args, /* copy_args */ + free_alnum_args, /* free_args */ + alnum_check_field, /* field_check */ + alnum_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_ALNUM = &builtin_alnum; + + diff --git a/lib/libform/type_alpha.c b/lib/libform/type_alpha.c new file mode 100644 index 000000000..7f35cc916 --- /dev/null +++ b/lib/libform/type_alpha.c @@ -0,0 +1,180 @@ +/* $NetBSD: type_alpha.c,v 1.11 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_alpha.c,v 1.11 2004/11/24 11:57:09 blymn Exp $"); + +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The alpha type handling. + */ + +typedef struct +{ + unsigned width; +} alpha_args; + +/* + * Create the alpha arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_alpha_args(va_list *args) +{ + alpha_args *new; + + new = (alpha_args *) malloc(sizeof(alpha_args)); + + if (new != NULL) + new->width = va_arg(*args, int); + + return (void *) new; +} + +/* + * Copy the alpha argument structure. + */ +static char * +copy_alpha_args(char *args) +{ + alpha_args *new; + + new = (alpha_args *) malloc(sizeof(alpha_args)); + + if (new != NULL) + new->width = ((alpha_args *) (void *) args)->width; + + return (void *) new; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_alpha_args(char *args) +{ + if (args != NULL) + free(args); +} + +/* + * Check the contents of the field buffer are alphanumeric only. + */ +static int +alpha_check_field(FIELD *field, char *args) +{ + int width, start, cur, end; + char *buf, *new; + + width = ((alpha_args *) (void *) field->args)->width; + buf = args; + start = 0; + + if (buf == NULL) + return FALSE; + + /* skip leading white space */ + while ((buf[start] != '\0') + && ((buf[start] == ' ') || (buf[start] == '\t'))) + start++; + + /* no good if we have hit the end */ + if (buf[start] == '\0') + return FALSE; + + /* find the end of the non-whitespace stuff */ + cur = start; + while(isalpha((unsigned char)buf[cur])) + cur++; + + /* no good if it exceeds the width */ + if ((cur - start) > width) + return FALSE; + + end = cur; + + /* check there is only trailing whitespace */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we are not at the end of the string */ + if (buf[cur] != '\0') + return FALSE; + + /* set buffer 0 to the new string */ + if ((new = (char *) malloc(sizeof(char) * (end - start))) == NULL) + return FALSE; + + if ((end - start) >= 1) { + strncpy(new, &buf[start], (size_t) (end - start - 1)); + new[end] = '\0'; + } else + new[0] = '\0'; + + + set_field_buffer(field, 0, new); + free(new); + + /* otherwise all was ok */ + return TRUE; +} + +/* + * Check the given character is alphabetic, return TRUE if it is. + */ +static int +alpha_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return (isalpha(c) ? TRUE : FALSE); +} + +static FIELDTYPE builtin_alpha = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_alpha_args, /* make_args */ + copy_alpha_args, /* copy_args */ + free_alpha_args, /* free_args */ + alpha_check_field, /* field_check */ + alpha_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_ALPHA = &builtin_alpha; + + diff --git a/lib/libform/type_enum.c b/lib/libform/type_enum.c new file mode 100644 index 000000000..1f1b5139a --- /dev/null +++ b/lib/libform/type_enum.c @@ -0,0 +1,369 @@ +/* $NetBSD: type_enum.c,v 1.11 2010/05/13 17:52:12 tnozaki Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_enum.c,v 1.11 2010/05/13 17:52:12 tnozaki Exp $"); + +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * Prototypes. + */ +static int +trim_blanks(char *field); + +/* + * The enum type handling. + */ + +typedef struct +{ + char **choices; + unsigned num_choices; + bool ignore_case; + bool exact; +} enum_args; + +/* + * Find the first non-blank character at the end of a field, return the + * index of that character. + */ +static int +trim_blanks(char *field) +{ + int i; + + i = (int) strlen(field); + if (i > 0) + i--; + else + return 0; + + while ((i > 0) && isblank((unsigned char)field[i])) + i--; + + return i; +} + +/* + * Create the enum arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_enum_args(va_list *args) +{ + enum_args *new; + char **choices; + + new = (enum_args *) malloc(sizeof(enum_args)); + + if (new != NULL) { + new->choices = va_arg(*args, char **); + new->ignore_case = (va_arg(*args, int)) ? TRUE : FALSE; + new->exact = (va_arg(*args, int)) ? TRUE : FALSE; + +#ifdef DEBUG + if (_formi_create_dbg_file() != E_OK) + return NULL; + fprintf(dbg, + "create_enum_args: ignore_case %d, no_blanks %d\n", + new->ignore_case, new->exact); +#endif + + /* count the choices we have */ + choices = new->choices; + new->num_choices = 0; + while (*choices != NULL) { +#ifdef DEBUG + fprintf(dbg, "create_enum_args: choice[%d] = \'%s\'\n", + new->num_choices, + new->choices[new->num_choices]); +#endif + new->num_choices++; + choices++; + } +#ifdef DEBUG + fprintf(dbg, "create_enum_args: have %d choices\n", + new->num_choices); +#endif + + } + + return (void *) new; +} + +/* + * Copy the enum argument structure. + */ +static char * +copy_enum_args(char *args) +{ + enum_args *new; + + new = (enum_args *) malloc(sizeof(enum_args)); + + if (new != NULL) + bcopy(args, new, sizeof(enum_args)); + + return (void *) new; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_enum_args(char *args) +{ + if (args != NULL) + free(args); +} + +/* + * Attempt to match the string in this to the choices given. Returns + * TRUE if match found otherwise FALSE. + * + */ +static bool +match_enum(char **choices, unsigned num_choices, bool ignore_case, + bool exact, char *this, unsigned *match_num) +{ + unsigned i, start, end, enum_start, blen, elen, enum_end; + bool cur_match; + + start = _formi_skip_blanks(this, 0); + end = trim_blanks(this); + + if (end >= start) + blen = (unsigned) (strlen(&this[start]) + - strlen(&this[end]) + 1); + else + blen = 0; + +#ifdef DEBUG + fprintf(dbg, "match_enum: start %d, blen %d\n", start, blen); +#endif + for (i = 0; i < num_choices; i++) { + enum_start = _formi_skip_blanks(choices[i], 0); + enum_end = trim_blanks(choices[i]); + + if (enum_end >= enum_start) + elen = (unsigned) (strlen(&choices[i][enum_start]) + - strlen(&choices[i][enum_end]) + 1); + else + elen = 0; + +#ifdef DEBUG + fprintf(dbg, "match_enum: checking choice \'%s\'\n", + choices[i]); + fprintf(dbg, "match_enum: enum_start %d, elen %d\n", + enum_start, elen); +#endif + + /* don't bother if we are after an exact match + * and the test length is not equal to the enum + * in question - it will never match. + */ + if ((exact == TRUE) && (blen != elen)) + continue; + + /* + * If the test length is longer than the enum + * length then there is no chance of a match + * so we skip. + */ + if ((exact != TRUE) && (blen > elen)) + continue; + + if (ignore_case) + cur_match = (strncasecmp(&choices[i][enum_start], + &this[start], + (size_t)blen) == 0) ? + TRUE : FALSE; + else + cur_match = (strncmp(&choices[i][enum_start], + &this[start], + (size_t) blen) == 0) ? + TRUE : FALSE; + +#ifdef DEBUG + fprintf(dbg, "match_enum: curmatch is %s\n", + (cur_match == TRUE)? "TRUE" : "FALSE"); +#endif + + if (cur_match == TRUE) { + *match_num = i; + return TRUE; + } + + } + +#ifdef DEBUG + fprintf(dbg, "match_enum: no match found\n"); +#endif + return FALSE; +} + +/* + * Check the contents of the field buffer match one of the enum strings only. + */ +static int +enum_check_field(FIELD *field, char *args) +{ + enum_args *ta; + unsigned match_num; + + if (args == NULL) + return FALSE; + + ta = (enum_args *) (void *) field->args; + + if (match_enum(ta->choices, ta->num_choices, ta->ignore_case, + ta->exact, args, &match_num) == TRUE) { +#ifdef DEBUG + fprintf(dbg, "enum_check_field: We matched, match_num %d\n", + match_num); + fprintf(dbg, "enum_check_field: buffer is \'%s\'\n", + ta->choices[match_num]); +#endif + set_field_buffer(field, 0, ta->choices[match_num]); + return TRUE; + } + + return FALSE; +} + +/* + * Get the next enum in the list of choices. + */ +static int +next_enum(FIELD *field, char *args) +{ + enum_args *ta; + unsigned cur_choice; + + if (args == NULL) + return FALSE; + + ta = (enum_args *) (void *) field->args; + +#ifdef DEBUG + fprintf(dbg, "next_enum: attempt to match \'%s\'\n", args); +#endif + + if (match_enum(ta->choices, ta->num_choices, ta->ignore_case, + ta->exact, args, &cur_choice) == FALSE) { +#ifdef DEBUG + fprintf(dbg, "next_enum: match failed\n"); +#endif + return FALSE; + } + +#ifdef DEBUG + fprintf(dbg, "next_enum: cur_choice is %d\n", cur_choice); +#endif + + cur_choice++; + + if (cur_choice >= ta->num_choices) + cur_choice = 0; + +#ifdef DEBUG + fprintf(dbg, "next_enum: cur_choice is %d on exit\n", + cur_choice); +#endif + + set_field_buffer(field, 0, ta->choices[cur_choice]); + return TRUE; +} + +/* + * Get the previous enum in the list of choices. + */ +static int +prev_enum(FIELD *field, char *args) +{ + enum_args *ta; + unsigned cur_choice; + + if (args == NULL) + return FALSE; + + ta = (enum_args *) (void *) field->args; + +#ifdef DEBUG + fprintf(dbg, "prev_enum: attempt to match \'%s\'\n", args); +#endif + + if (match_enum(ta->choices, ta->num_choices, ta->ignore_case, + ta->exact, args, &cur_choice) == FALSE) { +#ifdef DEBUG + fprintf(dbg, "prev_enum: match failed\n"); +#endif + return FALSE; + } + +#ifdef DEBUG + fprintf(dbg, "prev_enum: cur_choice is %d\n", cur_choice); +#endif + if (cur_choice == 0) + cur_choice = ta->num_choices - 1; + else + cur_choice--; + +#ifdef DEBUG + fprintf(dbg, "prev_enum: cur_choice is %d on exit\n", cur_choice); +#endif + + set_field_buffer(field, 0, ta->choices[cur_choice]); + return TRUE; +} + + +static FIELDTYPE builtin_enum = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_enum_args, /* make_args */ + copy_enum_args, /* copy_args */ + free_enum_args, /* free_args */ + enum_check_field, /* field_check */ + NULL, /* char_check */ + next_enum, /* next_choice */ + prev_enum /* prev_choice */ +}; + +FIELDTYPE *TYPE_ENUM = &builtin_enum; + + diff --git a/lib/libform/type_integer.c b/lib/libform/type_integer.c new file mode 100644 index 000000000..64d5be9cd --- /dev/null +++ b/lib/libform/type_integer.c @@ -0,0 +1,185 @@ +/* $NetBSD: type_integer.c,v 1.8 2004/10/28 21:14:52 dsl Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_integer.c,v 1.8 2004/10/28 21:14:52 dsl Exp $"); + +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The integer type handling. + */ + +typedef struct +{ + unsigned precision; + long min; + long max; +} integer_args; + +/* + * Create the integer arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_integer_args(va_list *args) +{ + integer_args *new; + + new = (integer_args *) malloc(sizeof(integer_args)); + + if (new != NULL) { + new->precision = va_arg(*args, unsigned); + new->min = va_arg(*args, long); + new->max = va_arg(*args, long); + } + + return (void *) new; +} + +/* + * Copy the integer argument structure. + */ +static char * +copy_integer_args(char *args) +{ + integer_args *new; + + new = (integer_args *) malloc(sizeof(integer_args)); + + if (new != NULL) + bcopy(args, new, sizeof(integer_args)); + + return (void *) new; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_integer_args(char *args) +{ + if (args != NULL) + free(args); +} + +/* + * Check the contents of the field buffer are digits only. + */ +static int +integer_check_field(FIELD *field, char *args) +{ + int cur; + long number, max, min; + int precision; + char *buf, *new_buf; + + if (args == NULL) + return FALSE; + + precision = ((integer_args *) (void *) field->args)->precision; + min = ((integer_args *) (void *) field->args)->min; + max = ((integer_args *) (void *) field->args)->max; + + buf = args; + cur = 0; + + /* skip leading white space */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we have hit the end */ + if (buf[cur] == '\0') + return FALSE; + + /* find the end of the digits but allow a leading + or - sign */ + if ((buf[cur] == '-') || (buf[cur] == '+')) + cur++; + + while(isdigit((unsigned char)buf[cur])) + cur++; + + /* check there is only trailing whitespace */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we are not at the end of the string */ + if (buf[cur] != '\0') + return FALSE; + + /* convert and range check the number...*/ + number = atol(buf); + if ((min > max) || ((number < min) || (number > max))) + return FALSE; + + if (asprintf(&new_buf, "%.*ld", precision, number) < 0) + return FALSE; + + /* re-set the field buffer to be the reformatted numeric */ + set_field_buffer(field, 0, new_buf); + + free(new_buf); + + /* otherwise all was ok */ + return TRUE; +} + +/* + * Check the given character is numeric, return TRUE if it is. + */ +static int +integer_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return ((isdigit(c) || (c == '-') || (c == '+')) ? TRUE : FALSE); +} + +static FIELDTYPE builtin_integer = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_integer_args, /* make_args */ + copy_integer_args, /* copy_args */ + free_integer_args, /* free_args */ + integer_check_field, /* field_check */ + integer_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_INTEGER = &builtin_integer; + + diff --git a/lib/libform/type_ipv4.c b/lib/libform/type_ipv4.c new file mode 100644 index 000000000..da1dd6a28 --- /dev/null +++ b/lib/libform/type_ipv4.c @@ -0,0 +1,211 @@ +/* $NetBSD: type_ipv4.c,v 1.10 2007/01/17 23:24:22 hubertf Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_ipv4.c,v 1.10 2007/01/17 23:24:22 hubertf Exp $"); + +#include +#include +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The IP v4 address type handling. + */ + +/* + * define the styles of address we can have, they are: + * FORMI_DOTTED_QUAD address of form aaa.bbb.ccc.ddd + * FORMI_HEX address of form 0xaabbccdd + * FORMI_CLASSLESS address of form aaa.bbb.ccc.ddd/ee + */ +#define FORMI_DOTTED_QUAD 0 +#define FORMI_HEX 1 +#define FORMI_CLASSLESS 2 + +/* + * Check the contents of the field buffer are a valid IPv4 address only. + */ +static int +ipv4_check_field(FIELD *field, char *args) +{ + char *buf, *buf1, *keeper, *p, *slash; + unsigned int vals[4], style, start, mask; + unsigned long hex_val, working; + int i; + + if (args == NULL) + return FALSE; + + if (asprintf(&keeper, "%s", args) < 0) + return FALSE; + +#ifdef DEBUG + fprintf(dbg, "ipv4_check_field: enter with args of %s\n", keeper); +#endif + style = FORMI_DOTTED_QUAD; + buf = keeper; + hex_val = 0; + mask = 0; + + if ((slash = index(buf, '/')) != NULL) + style = FORMI_CLASSLESS; + else { + start = _formi_skip_blanks(buf, 0); + if ((buf[start] != '\0') && (buf[start + 1] != '\0') && + (buf[start] == '0') && ((buf[start + 1] == 'x') || + (buf[start + 1] == 'X'))) + style = FORMI_HEX; + } + + switch (style) { + case FORMI_CLASSLESS: + *slash = '\0'; + slash++; + mask = atoi(slash); + if (mask > 32) + goto FAIL; + /* FALLTHROUGH */ + + case FORMI_DOTTED_QUAD: + for (i = 0; i < 4; i++) { + p = strsep(&buf, "."); + if ((p == NULL) || (*p == '\0')) + goto FAIL; + vals[i] = atoi(p); + if (vals[i] > 255) + goto FAIL; + } + break; + + + case FORMI_HEX: + errno = 0; + hex_val = strtoul(buf, NULL, 16); + if ((hex_val == ULONG_MAX) && (errno == ERANGE)) + goto FAIL; + + working = hex_val; + for (i = 3; i >= 0; i--) { + vals[i] = (unsigned int)(working & 0xffUL); + working = working >> 8; + } + break; + + } + + free(keeper); + + buf1 = NULL; + + switch (style) { + case FORMI_DOTTED_QUAD: + if (asprintf(&buf, "%d.%d.%d.%d", vals[0], vals[1], vals[2], + vals[3]) < 0) + return FALSE; + if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], + vals[2], vals[3]) < 0) + return FALSE; + break; + + case FORMI_CLASSLESS: + if (asprintf(&buf, "%d.%d.%d.%d/%d", vals[0], vals[1], + vals[2], vals[3], mask) < 0) + return FALSE; + if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], + vals[2], vals[3]) < 0) + return FALSE; + break; + + case FORMI_HEX: + if (asprintf(&buf, "0x%.8lx", hex_val) < 0) + return FALSE; + if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], + vals[2], vals[3]) < 0) + return FALSE; + break; + } + + /* re-set the field buffer to be the reformatted IPv4 address */ + set_field_buffer(field, 0, buf); + + /* + * Set the field buffer 1 to the dotted quad format regardless + * of the input format, only if buffer 1 exists. + */ + if (field->nbuf > 1) + set_field_buffer(field, 1, buf1); + +#ifdef DEBUG + fprintf(dbg, "ipv4_check_field: buf0 set to %s\n", buf); + fprintf(dbg, "ipv4_check_field: buf1 set to %s\n", buf1); +#endif + free(buf); + free(buf1); + + return TRUE; + + /* bail out point if we got a bad entry */ + FAIL: + free(keeper); + return FALSE; + +} + +/* + * Check the given character is numeric, return TRUE if it is. + */ +static int +ipv4_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') || + (c == '/'))? TRUE : FALSE; +} + +static FIELDTYPE builtin_ipv4 = { + _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + NULL, /* make_args */ + NULL, /* copy_args */ + NULL, /* free_args */ + ipv4_check_field, /* field_check */ + ipv4_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_IPV4 = &builtin_ipv4; + + diff --git a/lib/libform/type_ipv6.c b/lib/libform/type_ipv6.c new file mode 100644 index 000000000..cb3b0ddcf --- /dev/null +++ b/lib/libform/type_ipv6.c @@ -0,0 +1,123 @@ +/* $NetBSD: type_ipv6.c,v 1.10 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Many thanks to Jun-ichiro itojun Hagino for providing + * the sample code for the check field function, this function is 99.999% + * his code. + * + */ + +#include +__RCSID("$NetBSD: type_ipv6.c,v 1.10 2004/11/24 11:57:09 blymn Exp $"); + +#include +#include +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The IP v6 address type handling. + */ + +/* + * Check the contents of the field buffer are a valid Ipv6 address only. + */ +static int +ipv6_check_field(FIELD *field, char *args) +{ + char cleaned[NI_MAXHOST]; + struct addrinfo hints, *res; + const int niflags = NI_NUMERICHOST; + + if (args == NULL) + return FALSE; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; /* dummy */ + hints.ai_flags = AI_NUMERICHOST; + + if (getaddrinfo(args, "0", &hints, &res) != 0) { + /* no it is not an IPv6 address */ + return FALSE; + } + + if (res->ai_next) { + /* somehow the address resolved to multiple + * addresses - strange + */ + freeaddrinfo(res); + return FALSE; + } + + if (getnameinfo(res->ai_addr, res->ai_addrlen, cleaned, + (socklen_t) sizeof(cleaned), NULL, 0, niflags) != 0) { + freeaddrinfo(res); + return FALSE; + } + + freeaddrinfo(res); + + /* + * now we are sure host is an IPv6 address literal, and "cleaned" + * has the uniformly-formatted IPv6 address literal. Re-set the + * field buffer to be the reformatted IPv6 address + */ + set_field_buffer(field, 0, cleaned); + + return TRUE; +} + +/* + * Check the given character is numeric, return TRUE if it is. + */ +static int +ipv6_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return (isxdigit(c) || (c == '.') || (c == ':')) ? TRUE : FALSE; +} + +static FIELDTYPE builtin_ipv6 = { + _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + NULL, /* make_args */ + NULL, /* copy_args */ + NULL, /* free_args */ + ipv6_check_field, /* field_check */ + ipv6_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_IPV6 = &builtin_ipv6; + + diff --git a/lib/libform/type_numeric.c b/lib/libform/type_numeric.c new file mode 100644 index 000000000..2e2497386 --- /dev/null +++ b/lib/libform/type_numeric.c @@ -0,0 +1,220 @@ +/* $NetBSD: type_numeric.c,v 1.8 2004/10/28 21:14:52 dsl Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_numeric.c,v 1.8 2004/10/28 21:14:52 dsl Exp $"); + +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The numeric type handling. + */ + +typedef struct +{ + unsigned precision; + double min; + double max; +} numeric_args; + +/* + * Create the numeric arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_numeric_args(va_list *args) +{ + numeric_args *new; + + new = (numeric_args *) malloc(sizeof(numeric_args)); + + if (new != NULL) { + new->precision = va_arg(*args, unsigned); + new->min = va_arg(*args, double); + new->max = va_arg(*args, double); + } + + return (void *) new; +} + +/* + * Copy the numeric argument structure. + */ +static char * +copy_numeric_args(char *args) +{ + numeric_args *new; + + new = (numeric_args *) malloc(sizeof(numeric_args)); + + if (new != NULL) + bcopy(args, new, sizeof(numeric_args)); + + return (void *) new; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_numeric_args(char *args) +{ + if (args != NULL) + free(args); +} + +/* + * Check the contents of the field buffer are numeric only. A valid + * number is of the form nnnn[.mmmmm][Ee[+-]ddd] + */ +static int +numeric_check_field(FIELD *field, char *args) +{ + int cur; + double number, max, min; + int precision; + char *buf, *new_buf; + + if (args == NULL) + return FALSE; + + precision = ((numeric_args *) (void *) field->args)->precision; + min = ((numeric_args *) (void *) field->args)->min; + max = ((numeric_args *) (void *) field->args)->max; + + buf = args; + cur = 0; + + /* skip leading white space */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we have hit the end */ + if (buf[cur] == '\0') + return FALSE; + + /* find the end of the digits but allow a leading + or - sign, and + * a decimal point. + */ + if ((buf[cur] == '-') || (buf[cur] == '+')) + cur++; + + while(isdigit((unsigned char)buf[cur])) + cur++; + + /* if not at end of string then check for decimal... */ + if ((buf[cur] != '\0') && (buf[cur] == '.')) { + cur++; + /* check for more digits now.... */ + while(isdigit((unsigned char)buf[cur])) + cur++; + } + + /* check for an exponent */ + if ((buf[cur] != '\0') && + ((buf[cur] == 'E') || (buf[cur] == 'e'))) { + cur++; + if (buf[cur] == '\0') + return FALSE; + + /* allow a + or a - for exponent */ + if ((buf[cur] == '+') || (buf[cur] == '-')) + cur++; + + if (buf[cur] == '\0') + return FALSE; + + /* we expect a digit now */ + if (!isdigit((unsigned char)buf[cur])) + return FALSE; + + /* skip digits for the final time */ + while(isdigit((unsigned char)buf[cur])) + cur++; + } + + /* check there is only trailing whitespace */ + while ((buf[cur] != '\0') + && ((buf[cur] == ' ') || (buf[cur] == '\t'))) + cur++; + + /* no good if we are not at the end of the string */ + if (buf[cur] != '\0') + return FALSE; + + /* convert and range check the number...*/ + number = atof(buf); + if ((min < max) && ((number < min) || (number > max))) + return FALSE; + + if (asprintf(&new_buf, "%.*f", precision, number) < 0) + return FALSE; + + /* re-set the field buffer to be the reformatted numeric */ + set_field_buffer(field, 0, new_buf); + + free(new_buf); + + /* otherwise all was ok */ + return TRUE; +} + +/* + * Check the given character is numeric, return TRUE if it is. + */ +static int +numeric_check_char(/* ARGSUSED1 */ int c, char *args) +{ + return ((isdigit(c) || (c == '-') || (c == '+') + || (c == '.') || (c == 'e') || (c == 'E')) ? TRUE : FALSE); +} + +static FIELDTYPE builtin_numeric = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_numeric_args, /* make_args */ + copy_numeric_args, /* copy_args */ + free_numeric_args, /* free_args */ + numeric_check_field, /* field_check */ + numeric_check_char, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_NUMERIC = &builtin_numeric; + + diff --git a/lib/libform/type_regex.c b/lib/libform/type_regex.c new file mode 100644 index 000000000..866f59004 --- /dev/null +++ b/lib/libform/type_regex.c @@ -0,0 +1,129 @@ +/* $NetBSD: type_regex.c,v 1.7 2004/11/24 11:57:09 blymn Exp $ */ + +/*- + * Copyright (c) 1998-1999 Brett Lymn + * (blymn@baea.com.au, brett_lymn@yahoo.com.au) + * All rights reserved. + * + * This code has been donated to The NetBSD Foundation by the Author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +#include +__RCSID("$NetBSD: type_regex.c,v 1.7 2004/11/24 11:57:09 blymn Exp $"); + +#include +#include +#include +#include "form.h" +#include "internals.h" + +/* + * The regex type handling. + */ + +typedef struct +{ + regex_t compiled; + unsigned references; +} regex_args; + +/* + * Create the regex arguments structure from the given args. Return NULL + * if the call fails, otherwise return a pointer to the structure allocated. + */ +static char * +create_regex_args(va_list *args) +{ + regex_args *new; + char *expression; + + new = (regex_args *) malloc(sizeof(regex_args)); + + if (new != NULL) { + new->references = 1; + expression = va_arg(*args, char *); + if ((regcomp(&new->compiled, expression, + (REG_EXTENDED | REG_NOSUB | REG_NEWLINE))) != 0) { + free(new); + return NULL; + } + } + + return (void *) new; +} + +/* + * Copy the regex argument structure. + */ +static char * +copy_regex_args(char *args) +{ + ((regex_args *) (void *) args)->references++; + + return (void *) args; +} + +/* + * Free the allocated storage associated with the type arguments. + */ +static void +free_regex_args(char *args) +{ + if (args != NULL) { + ((regex_args *) (void *) args)->references--; + if (((regex_args *) (void *) args)->references == 0) + free(args); + } +} + +/* + * Check the contents of the field buffer match the regex. + */ +static int +regex_check_field(FIELD *field, char *args) +{ + if ((args != NULL) && + (regexec(&((regex_args *) (void *) field->args)->compiled, + args, (size_t) 0, NULL, 0) == 0)) + return TRUE; + + return FALSE; +} + +static FIELDTYPE builtin_regex = { + _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ + 0, /* refcount */ + NULL, /* link */ + create_regex_args, /* make_args */ + copy_regex_args, /* copy_args */ + free_regex_args, /* free_args */ + regex_check_field, /* field_check */ + NULL, /* char_check */ + NULL, /* next_choice */ + NULL /* prev_choice */ +}; + +FIELDTYPE *TYPE_REGEXP = &builtin_regex; + + diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 8e7c07838..5082b3f92 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -82,6 +82,7 @@ 2012/10/17 12:00:00,lib/libcrypt 2012/10/17 12:00:00,lib/libcurses 2012/10/17 12:00:00,lib/libedit +2012/10/17 12:00:00,lib/libform 2012/10/17 12:00:00,lib/libm 2012/10/17 12:00:00,lib/libmenu 2011/09/30 22:08:19,lib/libprop