#ifdef RCSID static char RCSid[] = "$Header$"; #endif /* * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. * * Please see the accompanying license file, LICENSE.TXT, for information * on using and copying this software. */ /* Name indlg_tx.c - input dialog - formatted text-only version Function Implements the input dialog function using formatted text Notes Only one of indlg_tx or indlg_os should be included in a given executable. The choice depends on whether a system-level dialog is available or not. If no system-level dialog is available, include indlg_tx, which provides an implementation using formatted text. If a system-level dialog is available, use indlg_os, which calls os_input_dialog(). This file exists in the portable layer, rather than in the OS layer, so that we can provide an implementation using formatted text. An OS-layer implementation could not provide formatted text. Modified 09/27/99 MJRoberts - Creation */ #include #include #include #include "std.h" #include "os.h" #include "tio.h" /* ------------------------------------------------------------------------ */ /* * Text-mode os_input_dialog implementation */ int tio_input_dialog(int icon_id, const char *prompt, int standard_button_set, const char **buttons, int button_count, int default_index, int cancel_index) { /* ignore the icon ID - we can't display an icon in text mode */ VARUSED(icon_id); /* keep going until we get a valid response */ for (;;) { int i; char buf[256]; const char *p; const char *cur; char *resp; int match_cnt; int last_found; static const struct { const char *buttons[3]; int button_count; } std_btns[] = { { { "&OK" }, 1 }, { { "&OK", "&Cancel" }, 2 }, { { "&Yes", "&No" }, 2 }, { { "&Yes", "&No", "&Cancel" }, 3 } }; /* * if we have a standard button set selected, get our button * labels */ switch(standard_button_set) { case 0: /* use the explicit buttons provided */ break; case OS_INDLG_OK: i = 0; use_std_btns: /* use the selected standard button set */ buttons = (const char **)std_btns[i].buttons; button_count = std_btns[i].button_count; break; case OS_INDLG_OKCANCEL: i = 1; goto use_std_btns; case OS_INDLG_YESNO: i = 2; goto use_std_btns; case OS_INDLG_YESNOCANCEL: i = 3; goto use_std_btns; default: /* * we don't recognize other standard button sets - return an * error */ return 0; } /* * if there are no buttons defined, they'll never be able to * respond, so we'd just loop forever - rather than let that * happen, return failure */ if (button_count == 0) return 0; /* display a newline and the prompt string */ outformat("\\n"); outformat((char *)prompt); outformat(" "); /* display the response */ for (i = 0 ; i < button_count ; ++i) { /* * display a slash to separate responses, if this isn't the * first one */ if (i != 0) outformat("/"); /* get the current button */ cur = buttons[i]; /* * Look for a "&" in the response string. If we find it, * remove the "&" and enclose the shortcut key in parens. */ for (p = cur ; *p != '&' && *p != '\0' ; ++p) ; /* if we found the "&", put the next character in parens */ if (*p == '&') { /* reformat the response string */ sprintf(buf, "%.*s(%c)%s", (int)(p - cur), cur, *(p+1), p+2); /* display it */ outformat(buf); } else { /* no '&' - just display the response string as-is */ outformat((char *)cur); } } /* if we're in HTML mode, switch to input font */ if (tio_is_html_mode()) outformat(""); /* read the response */ getstring(" >", buf, sizeof(buf)); /* if we're in HTML mode, close the input font tag */ if (tio_is_html_mode()) outformat(""); /* skip any leading spaces in the reply */ for (resp = buf ; t_isspace(*resp) ; ++resp) ; /* if it's one character, check it against the shortcut keys */ if (strlen(resp) == 1) { /* scan the responses */ for (i = 0 ; i < button_count ; ++i) { /* look for a '&' in this button */ for (p = buttons[i] ; *p != '&' && *p != '\0' ; ++p) ; /* if we found the '&', check the shortcut */ if (*p == '&' && toupper(*(p+1)) == toupper(*resp)) { /* * this is the one - return the current index * (bumping it by one to get a 1-based value) */ return i + 1; } } } /* * Either it's not a one-character reply, or it didn't match a * short-cut - check it against the leading substrings of the * responses. If it matches exactly one of the responses in its * leading substring, use that response. */ for (i = 0, match_cnt = 0 ; i < button_count ; ++i) { const char *p1; const char *p2; /* * compare this response to the user's response; skip any * '&' in the button label */ for (p1 = resp, p2 = buttons[i] ; *p1 != '\0' && *p2 != '\0' ; ++p1, ++p2) { /* if this is a '&' in the button label, skip it */ if (*p2 == '&') ++p2; /* if these characters don't match, it's no match */ if (toupper(*p1) != toupper(*p2)) break; } /* * if we reached the end of the user's response, we have a * match in the leading substring - count it and remember * this as the last one, but keep looking, since we need to * make sure we don't have any other matches */ if (*p1 == '\0') { ++match_cnt; last_found = i; } } /* * if we found exactly one match, return it (adjusting to a * 1-based index); if we found more or less than one match, it's * not a valid response, so start over with a new prompt */ if (match_cnt == 1) return last_found + 1; } }