/*
* options.c
* Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
*
* Description:
* Read and write the options
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__riscos)
#include "DeskLib:Error.h"
#include "DeskLib:Wimp.h"
#else
#include <stdlib.h>
#if defined(__dos) || defined(N_PLAT_NLM)
extern int getopt(int, char **, const char *);
#else
#include <unistd.h>
#endif /* __dos */
#endif /* __riscos */
#include "antiword.h"

#if defined(__riscos)
#define PARAGRAPH_BREAK         "set paragraph_break=%d"
#define AUTOFILETYPE            "set autofiletype_allowed=%d"
#define USE_OUTLINEFONTS        "set use_outlinefonts=%d"
#define SHOW_IMAGES             "set show_images=%d"
#define HIDE_HIDDEN_TEXT        "set hide_hidden_text=%d"
#define SCALE_FACTOR_START      "set scale_factor_start=%d"
#else
#define LEAFNAME_SIZE           (32+1)
#endif /* __riscos */

/* Current values for options */
static options_type     tOptionsCurr;
#if defined(__riscos)
/* Temporary values for options */
static options_type     tOptionsTemp;
#else
typedef struct papersize_tag {
       char    szName[16];     /* Papersize name */
       USHORT  usWidth;        /* In points */
       USHORT  usHeight;       /* In points */
} papersize_type;

static const papersize_type atPaperSizes[] = {
       {       "10x14",         720,   1008    },
       {       "a3",            842,   1191    },
       {       "a4",            595,    842    },
       {       "a5",            420,    595    },
       {       "b4",            729,   1032    },
       {       "b5",            516,    729    },
       {       "executive",     540,    720    },
       {       "folio",         612,    936    },
       {       "legal",         612,   1008    },
       {       "letter",        612,    792    },
       {       "note",          540,    720    },
       {       "quarto",        610,    780    },
       {       "statement",     396,    612    },
       {       "tabloid",       792,   1224    },
       {       "",                0,      0    },
};
#endif /* __riscos */
/* Default values for options */
static const options_type       tOptionsDefault = {
       DEFAULT_SCREEN_WIDTH,
#if defined(__riscos)
       conversion_draw,
#else
       conversion_text,
#endif /* __riscos */
       TRUE,
       TRUE,
       FALSE,
       encoding_latin_1,
       INT_MAX,
       INT_MAX,
       level_default,
#if defined(__riscos)
       TRUE,
       DEFAULT_SCALE_FACTOR,
#endif /* __riscos */
};


#if !defined(__riscos)
/*
* bCorrectPapersize - see if the papersize is correct
*
* TRUE if the papersize is correct, otherwise FALSE
*/
static BOOL
bCorrectPapersize(const char *szName, conversion_type eConversionType)
{
       const papersize_type    *pPaperSize;

       for (pPaperSize = atPaperSizes;
            pPaperSize->szName[0] != '\0';
            pPaperSize++) {
               if (!STRCEQ(pPaperSize->szName,  szName)) {
                       continue;
               }
               DBG_DEC(pPaperSize->usWidth);
               DBG_DEC(pPaperSize->usHeight);
               tOptionsCurr.eConversionType = eConversionType;
               tOptionsCurr.iPageHeight = (int)pPaperSize->usHeight;
               tOptionsCurr.iPageWidth = (int)pPaperSize->usWidth;
               return TRUE;
       }
       return FALSE;
} /* end of bCorrectPapersize */

/*
* szCreateSuffix - create a suffix for the file
*
* Returns the suffix
*/
static const char *
szCreateSuffix(const char *szLeafname)
{
       const char      *pcDot;

       pcDot = strrchr(szLeafname, '.');
       if (pcDot != NULL && STRCEQ(pcDot, ".txt")) {
               /* There is already a .txt suffix, no need for another one */
               return "";
       }
       return ".txt";
} /* end of szCreateSuffix */

/*
* eMappingFile2Encoding - convert the mapping file to an encoding
*/
static encoding_type
eMappingFile2Encoding(const char *szLeafname)
{
       char    szMappingFile[LEAFNAME_SIZE+4];

       fail(szLeafname == NULL);

       if (strlen(szLeafname) + 4 >= sizeof(szMappingFile)) {
               DBG_MSG(szLeafname);
               return encoding_latin_1;
       }

       sprintf(szMappingFile, "%s%s", szLeafname, szCreateSuffix(szLeafname));

       DBG_MSG(szMappingFile);

       if (STRCEQ(szMappingFile, MAPPING_FILE_UTF_8)) {
               return encoding_utf_8;
       }
       if (STRCEQ(szMappingFile, MAPPING_FILE_CP852) ||
           STRCEQ(szMappingFile, MAPPING_FILE_CP1250) ||
           STRCEQ(szMappingFile, MAPPING_FILE_8859_2)) {
               return encoding_latin_2;
       }
       if (STRCEQ(szMappingFile, MAPPING_FILE_KOI8_R) ||
           STRCEQ(szMappingFile, MAPPING_FILE_KOI8_U) ||
           STRCEQ(szMappingFile, MAPPING_FILE_CP866) ||
           STRCEQ(szMappingFile, MAPPING_FILE_CP1251) ||
           STRCEQ(szMappingFile, MAPPING_FILE_8859_5)) {
               return encoding_cyrillic;
       }
       return encoding_latin_1;
} /* end of eMappingFile2Encoding */
#endif /* !__riscos */

/*
* pOpenCharacterMappingFile - open the mapping file
*
* Returns the file pointer or NULL
*/
static FILE *
pOpenCharacterMappingFile(const char *szLeafname)
{
#if !defined(__riscos)
       FILE    *pFile;
       const char      *szHome, *szAntiword, *szSuffix;
       size_t  tFilenameLen;
       char    szMappingFile[PATH_MAX+1];
#endif /* !__riscos */

       if (szLeafname == NULL || szLeafname[0] == '\0') {
               return NULL;
       }

       DBG_MSG(szLeafname);

#if defined(__riscos)
       return fopen(szLeafname, "r");
#else
       /* Set the suffix */
       szSuffix = szCreateSuffix(szLeafname);

       /* Set length */
       tFilenameLen = strlen(szLeafname) + strlen(szSuffix);

       /* Try the environment version of the mapping file */
       szAntiword = szGetAntiwordDirectory();
       if (szAntiword != NULL && szAntiword[0] != '\0') {
           if (strlen(szAntiword) + tFilenameLen <
               sizeof(szMappingFile) -
               sizeof(FILE_SEPARATOR)) {
                       sprintf(szMappingFile,
                               "%s" FILE_SEPARATOR "%s%s",
                               szAntiword, szLeafname, szSuffix);
                       DBG_MSG(szMappingFile);
                       pFile = fopen(szMappingFile, "r");
                       if (pFile != NULL) {
                               return pFile;
                       }
               } else {
                       werr(0, "Environment mappingfilename ignored");
               }
       }

       /* Try the local version of the mapping file */
       szHome = szGetHomeDirectory();
       if (strlen(szHome) + tFilenameLen <
           sizeof(szMappingFile) -
           sizeof(ANTIWORD_DIR) -
           2 * sizeof(FILE_SEPARATOR)) {
               sprintf(szMappingFile,
                       "%s" FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR "%s%s",
                       szHome, szLeafname, szSuffix);
               DBG_MSG(szMappingFile);
               pFile = fopen(szMappingFile, "r");
               if (pFile != NULL) {
                       return pFile;
               }
       } else {
               werr(0, "Local mappingfilename too long, ignored");
       }

       /* Try the global version of the mapping file */
       if (tFilenameLen <
           sizeof(szMappingFile) -
           sizeof(GLOBAL_ANTIWORD_DIR) -
           sizeof(FILE_SEPARATOR)) {
               sprintf(szMappingFile,
                       GLOBAL_ANTIWORD_DIR FILE_SEPARATOR "%s%s",
                       szLeafname, szSuffix);
               DBG_MSG(szMappingFile);
               pFile = fopen(szMappingFile, "r");
               if (pFile != NULL) {
                       return pFile;
               }
       } else {
               werr(0, "Global mappingfilename too long, ignored");
       }
       werr(0, "I can't open your mapping file (%s%s)\n"
               "It is not in '%s" FILE_SEPARATOR ANTIWORD_DIR "' nor in '"
               GLOBAL_ANTIWORD_DIR "'.", szLeafname, szSuffix, szHome);
       return NULL;
#endif /* __riscos */
} /* end of pOpenCharacterMappingFile */

/*
* vCloseCharacterMappingFile - close the mapping file
*/
static void
vCloseCharacterMappingFile(FILE *pFile)
{
       (void)fclose(pFile);
} /* end of pCloseCharacterMappingFile */


/*
* iReadOptions - read options
*
* returns:     -1: error
*               0: help
*              >0: index first file argument
*/
int
iReadOptions(int argc, char **argv)
{
#if defined(__riscos)
       FILE    *pFile;
       const char      *szAlphabet;
       int     iAlphabet;
       char    szLine[81];
#else
       extern  char    *optarg;
       extern int      optind;
       char    *pcChar, *szTmp;
       int     iChar;
       char    szLeafname[LEAFNAME_SIZE];
#endif /* __riscos */
       FILE    *pCharacterMappingFile;
       int     iTmp;
       BOOL    bSuccess;

       DBG_MSG("iReadOptions");

/* Defaults */
       tOptionsCurr = tOptionsDefault;

#if defined(__riscos)
/* Choices file */
       pFile = fopen("<AntiWord$ChoicesFile>", "r");
       DBG_MSG_C(pFile == NULL, "Choices file not found");
       DBG_HEX_C(pFile != NULL, pFile);
       if (pFile != NULL) {
               while (fgets(szLine, (int)sizeof(szLine), pFile) != NULL) {
                       DBG_MSG(szLine);
                       if (szLine[0] == '#' ||
                           szLine[0] == '\r' ||
                           szLine[0] == '\n') {
                               continue;
                       }
                       if (sscanf(szLine, PARAGRAPH_BREAK, &iTmp) == 1 &&
                           (iTmp == 0 ||
                           (iTmp >= MIN_SCREEN_WIDTH &&
                            iTmp <= MAX_SCREEN_WIDTH))) {
                               tOptionsCurr.iParagraphBreak = iTmp;
                               DBG_DEC(tOptionsCurr.iParagraphBreak);
                       } else if (sscanf(szLine, AUTOFILETYPE, &iTmp)
                                                               == 1) {
                               tOptionsCurr.bAutofiletypeAllowed =
                                                               iTmp != 0;
                               DBG_DEC(tOptionsCurr.bAutofiletypeAllowed);
                       } else if (sscanf(szLine, USE_OUTLINEFONTS, &iTmp)
                                                               == 1) {
                               tOptionsCurr.eConversionType =
                                       iTmp == 0 ?
                                       conversion_text : conversion_draw;
                               DBG_DEC(tOptionsCurr.eConversionType);
                       } else if (sscanf(szLine, SHOW_IMAGES, &iTmp)
                                                               == 1) {
                               tOptionsCurr.eImageLevel = iTmp != 0 ?
                                       level_default : level_no_images;
                       } else if (sscanf(szLine, HIDE_HIDDEN_TEXT, &iTmp)
                                                               == 1) {
                               tOptionsCurr.bHideHiddenText = iTmp != 0;
                               DBG_DEC(tOptionsCurr.bHideHiddenText);
                       } else if (sscanf(szLine, SCALE_FACTOR_START, &iTmp)
                                                               == 1) {
                               if (iTmp >= MIN_SCALE_FACTOR &&
                                   iTmp <= MAX_SCALE_FACTOR) {
                                       tOptionsCurr.iScaleFactor = iTmp;
                                       DBG_DEC(tOptionsCurr.iScaleFactor);
                               }
                       }
               }
               (void)fclose(pFile);
       }
       iAlphabet = iReadCurrentAlphabetNumber();
       switch (iAlphabet) {
       case 101:       /* ISO-8859-1 aka Latin1 */
               szAlphabet = "<AntiWord$Latin1>";
               break;
       case 112:       /* ISO-8859-15 aka Latin9 */
               szAlphabet = "<AntiWord$Latin9>";
               break;
       default:
               werr(0, "Alphabet '%d' is not supported", iAlphabet);
               return -1;
       }
       pCharacterMappingFile = pOpenCharacterMappingFile(szAlphabet);
       if (pCharacterMappingFile != NULL) {
               bSuccess = bReadCharacterMappingTable(pCharacterMappingFile);
               vCloseCharacterMappingFile(pCharacterMappingFile);
       } else {
               bSuccess = FALSE;
       }
       return bSuccess ? 1 : -1;
#else
/* Environment */
       szTmp = getenv("COLUMNS");
       if (szTmp != NULL) {
               DBG_MSG(szTmp);
               iTmp = (int)strtol(szTmp, &pcChar, 10);
               if (*pcChar == '\0') {
                       iTmp -= 4;      /* This is for the edge */
                       if (iTmp < MIN_SCREEN_WIDTH) {
                               iTmp = MIN_SCREEN_WIDTH;
                       } else if (iTmp > MAX_SCREEN_WIDTH) {
                               iTmp = MAX_SCREEN_WIDTH;
                       }
                       tOptionsCurr.iParagraphBreak = iTmp;
                       DBG_DEC(tOptionsCurr.iParagraphBreak);
               }
       }
       strncpy(szLeafname, szGetDefaultMappingFile(), sizeof(szLeafname) - 1);
       szLeafname[sizeof(szLeafname) - 1] = '\0';
/* Command line */
       while ((iChar = getopt(argc, argv, "La:fhi:m:p:rstw:x:")) != -1) {
               switch (iChar) {
               case 'L':
                       tOptionsCurr.bUseLandscape = TRUE;
                       break;
               case 'a':
                       if (!bCorrectPapersize(optarg, conversion_pdf)) {
                               werr(0, "-a without a valid papersize");
                               return -1;
                       }
                       break;
               case 'f':
                       tOptionsCurr.eConversionType = conversion_fmt_text;
                       break;
               case 'h':
                       return 0;
               case 'i':
                       iTmp = (int)strtol(optarg, &pcChar, 10);
                       if (*pcChar != '\0') {
                               break;
                       }
                       switch (iTmp) {
                       case 0:
                               tOptionsCurr.eImageLevel = level_gs_special;
                               break;
                       case 1:
                               tOptionsCurr.eImageLevel = level_no_images;
                               break;
                       case 2:
                               tOptionsCurr.eImageLevel = level_ps_2;
                               break;
                       case 3:
                               tOptionsCurr.eImageLevel = level_ps_3;
                               break;
                       default:
                               tOptionsCurr.eImageLevel = level_default;
                               break;
                       }
                       DBG_DEC(tOptionsCurr.eImageLevel);
                       break;
               case 'm':
                       if (tOptionsCurr.eConversionType == conversion_xml) {
                               werr(0, "XML doesn't need a mapping file");
                               break;
                       }
                       strncpy(szLeafname, optarg, sizeof(szLeafname) - 1);
                       szLeafname[sizeof(szLeafname) - 1] = '\0';
                       DBG_MSG(szLeafname);
                       break;
               case 'p':
                       if (!bCorrectPapersize(optarg, conversion_ps)) {
                               werr(0, "-p without a valid papersize");
                               return -1;
                       }
                       break;
               case 'r':
                       tOptionsCurr.bRemoveRemovedText = FALSE;
                       break;
               case 's':
                       tOptionsCurr.bHideHiddenText = FALSE;
                       break;
               case 't':
                       tOptionsCurr.eConversionType = conversion_text;
                       break;
               case 'w':
                       iTmp = (int)strtol(optarg, &pcChar, 10);
                       if (*pcChar == '\0') {
                               if (iTmp != 0 && iTmp < MIN_SCREEN_WIDTH) {
                                       iTmp = MIN_SCREEN_WIDTH;
                               } else if (iTmp > MAX_SCREEN_WIDTH) {
                                       iTmp = MAX_SCREEN_WIDTH;
                               }
                               tOptionsCurr.iParagraphBreak = iTmp;
                               DBG_DEC(tOptionsCurr.iParagraphBreak);
                       }
                       break;
               case 'x':
                       if (STREQ(optarg, "db")) {
                               tOptionsCurr.iParagraphBreak = 0;
                               tOptionsCurr.eConversionType = conversion_xml;
                               strcpy(szLeafname, MAPPING_FILE_UTF_8);
                       } else {
                               werr(0, "-x %s is not supported", optarg);
                               return -1;
                       }
                       break;
               default:
                       return -1;
               }
       }

       tOptionsCurr.eEncoding = eMappingFile2Encoding(szLeafname);
       DBG_DEC(tOptionsCurr.eEncoding);

       if (tOptionsCurr.eConversionType == conversion_ps &&
           tOptionsCurr.eEncoding == encoding_utf_8) {
               werr(0,
               "The combination PostScript and UTF-8 is not supported");
               return -1;
       }

       if (tOptionsCurr.eConversionType == conversion_pdf &&
           tOptionsCurr.eEncoding == encoding_utf_8) {
               werr(0,
               "The combination PDF and UTF-8 is not supported");
               return -1;
       }

       if (tOptionsCurr.eConversionType == conversion_pdf &&
           tOptionsCurr.eEncoding == encoding_cyrillic) {
               werr(0,
               "The combination PDF and Cyrillic is not supported");
               return -1;
       }

       if (tOptionsCurr.eConversionType == conversion_ps ||
           tOptionsCurr.eConversionType == conversion_pdf) {
               /* PostScript or PDF mode */
               if (tOptionsCurr.bUseLandscape) {
                       /* Swap the page height and width */
                       iTmp = tOptionsCurr.iPageHeight;
                       tOptionsCurr.iPageHeight = tOptionsCurr.iPageWidth;
                       tOptionsCurr.iPageWidth = iTmp;
               }
               /* The paragraph break depends on the width of the paper */
               tOptionsCurr.iParagraphBreak = iMilliPoints2Char(
                       (long)tOptionsCurr.iPageWidth * 1000 -
                       lDrawUnits2MilliPoints(
                               PS_LEFT_MARGIN + PS_RIGHT_MARGIN));
               DBG_DEC(tOptionsCurr.iParagraphBreak);
       }

       pCharacterMappingFile = pOpenCharacterMappingFile(szLeafname);
       if (pCharacterMappingFile != NULL) {
               bSuccess = bReadCharacterMappingTable(pCharacterMappingFile);
               vCloseCharacterMappingFile(pCharacterMappingFile);
       } else {
               bSuccess = FALSE;
       }
       return bSuccess ? optind : -1;
#endif /* __riscos */
} /* end of iReadOptions */

/*
* vGetOptions - get a copy of the current option values
*/
void
vGetOptions(options_type *pOptions)
{
       fail(pOptions == NULL);

       *pOptions = tOptionsCurr;
} /* end of vGetOptions */

#if defined(__riscos)
/*
* vWriteOptions - write the current options to the Options file
*/
static void
vWriteOptions(void)
{
       FILE    *pFile;
       char    *szOptionsFile;

       TRACE_MSG("vWriteOptions");

       szOptionsFile = getenv("AntiWord$ChoicesSave");
       if (szOptionsFile == NULL) {
               werr(0, "Warning: Name of the Choices file not found");
               return;
       }
       if (!bMakeDirectory(szOptionsFile)) {
               werr(0,
               "Warning: I can't make a directory for the Choices file");
               return;
       }
       pFile = fopen(szOptionsFile, "w");
       if (pFile == NULL) {
               werr(0, "Warning: I can't write the Choices file");
               return;
       }
       (void)fprintf(pFile, PARAGRAPH_BREAK"\n",
               tOptionsCurr.iParagraphBreak);
       (void)fprintf(pFile, AUTOFILETYPE"\n",
               tOptionsCurr.bAutofiletypeAllowed);
       (void)fprintf(pFile, USE_OUTLINEFONTS"\n",
               tOptionsCurr.eConversionType == conversion_text ? 0 : 1);
       (void)fprintf(pFile, SHOW_IMAGES"\n",
               tOptionsCurr.eImageLevel == level_no_images ? 0 : 1);
       (void)fprintf(pFile, HIDE_HIDDEN_TEXT"\n",
               tOptionsCurr.bHideHiddenText);
       (void)fprintf(pFile, SCALE_FACTOR_START"\n",
               tOptionsCurr.iScaleFactor);
       (void)fclose(pFile);
} /* end of vWriteOptions */

/*
* vChoicesOpenAction - action to be taken when the Choices window opens
*/
void
vChoicesOpenAction(window_handle tWindow)
{
       TRACE_MSG("vChoicesOpenAction");

       tOptionsTemp = tOptionsCurr;
       if (tOptionsTemp.iParagraphBreak == 0) {
               vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, FALSE);
               vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, TRUE);
               vUpdateWriteableNumber(tWindow, CHOICES_BREAK_WRITEABLE,
                                       DEFAULT_SCREEN_WIDTH);
       } else {
               vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, TRUE);
               vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, FALSE);
               vUpdateWriteableNumber(tWindow,
                       CHOICES_BREAK_WRITEABLE,
                       tOptionsTemp.iParagraphBreak);
       }
       vUpdateRadioButton(tWindow, CHOICES_AUTOFILETYPE_BUTTON,
                                       tOptionsTemp.bAutofiletypeAllowed);
       vUpdateRadioButton(tWindow, CHOICES_HIDDEN_TEXT_BUTTON,
                                       tOptionsTemp.bHideHiddenText);
       if (tOptionsTemp.eConversionType == conversion_draw) {
               vUpdateRadioButton(tWindow,
                       CHOICES_WITH_IMAGES_BUTTON,
                       tOptionsTemp.eImageLevel != level_no_images);
               vUpdateRadioButton(tWindow,
                       CHOICES_NO_IMAGES_BUTTON,
                       tOptionsTemp.eImageLevel == level_no_images);
               vUpdateRadioButton(tWindow,
                       CHOICES_TEXTONLY_BUTTON, FALSE);
       } else {
               vUpdateRadioButton(tWindow,
                       CHOICES_WITH_IMAGES_BUTTON, FALSE);
               vUpdateRadioButton(tWindow,
                       CHOICES_NO_IMAGES_BUTTON, FALSE);
               vUpdateRadioButton(tWindow,
                       CHOICES_TEXTONLY_BUTTON, TRUE);
       }
       vUpdateWriteableNumber(tWindow,
               CHOICES_SCALE_WRITEABLE, tOptionsTemp.iScaleFactor);
       TRACE_MSG("end of vChoicesOpenAction");
} /* end of vChoicesOpenAction */

/*
* vDefaultButtonAction - action when the default button is clicked
*/
static void
vDefaultButtonAction(window_handle tWindow)
{
       TRACE_MSG("vDefaultButtonAction");

       tOptionsTemp = tOptionsDefault;
       vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, TRUE);
       vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, FALSE);
       vUpdateWriteableNumber(tWindow, CHOICES_BREAK_WRITEABLE,
                       tOptionsTemp.iParagraphBreak);
       vUpdateRadioButton(tWindow, CHOICES_AUTOFILETYPE_BUTTON,
                       tOptionsTemp.bAutofiletypeAllowed);
       vUpdateRadioButton(tWindow, CHOICES_HIDDEN_TEXT_BUTTON,
                       tOptionsTemp.bHideHiddenText);
       vUpdateRadioButton(tWindow, CHOICES_WITH_IMAGES_BUTTON,
                       tOptionsTemp.eConversionType == conversion_draw &&
                       tOptionsTemp.eImageLevel != level_no_images);
       vUpdateRadioButton(tWindow, CHOICES_NO_IMAGES_BUTTON,
                       tOptionsTemp.eConversionType == conversion_draw &&
                       tOptionsTemp.eImageLevel == level_no_images);
       vUpdateRadioButton(tWindow, CHOICES_TEXTONLY_BUTTON,
                       tOptionsTemp.eConversionType == conversion_text);
       vUpdateWriteableNumber(tWindow, CHOICES_SCALE_WRITEABLE,
                       tOptionsTemp.iScaleFactor);
} /* end of vDefaultButtonAction */

/*
* vApplyButtonAction - action to be taken when the OK button is clicked
*/
static void
vApplyButtonAction(void)
{
       TRACE_MSG("vApplyButtonAction");

       tOptionsCurr = tOptionsTemp;
} /* end of vApplyButtonAction */

/*
* vSaveButtonAction - action to be taken when the save button is clicked
*/
static void
vSaveButtonAction(void)
{
       TRACE_MSG("vSaveButtonAction");

       vApplyButtonAction();
       vWriteOptions();
} /* end of vSaveButtonAction */

/*
* vSetParagraphBreak - set the paragraph break to the given number
*/
static void
vSetParagraphBreak(window_handle tWindow, int iNumber)
{
       tOptionsTemp.iParagraphBreak = iNumber;
       if (tOptionsTemp.iParagraphBreak == 0) {
               return;
       }
       vUpdateWriteableNumber(tWindow,
                       CHOICES_BREAK_WRITEABLE,
                       tOptionsTemp.iParagraphBreak);
} /* end of vSetParagraphBreak */

/*
* vChangeParagraphBreak - change the paragraph break with the given number
*/
static void
vChangeParagraphBreak(window_handle tWindow, int iNumber)
{
       int     iTmp;

       iTmp = tOptionsTemp.iParagraphBreak + iNumber;
       if (iTmp < MIN_SCREEN_WIDTH || iTmp > MAX_SCREEN_WIDTH) {
               /* Ignore */
               return;
       }
       tOptionsTemp.iParagraphBreak = iTmp;
       vUpdateWriteableNumber(tWindow,
                       CHOICES_BREAK_WRITEABLE,
                       tOptionsTemp.iParagraphBreak);
} /* end of vChangeParagraphBreak */

/*
* vChangeAutofiletype - invert the permission to autofiletype
*/
static void
vChangeAutofiletype(window_handle tWindow)
{
       tOptionsTemp.bAutofiletypeAllowed =
                               !tOptionsTemp.bAutofiletypeAllowed;
       vUpdateRadioButton(tWindow,
                       CHOICES_AUTOFILETYPE_BUTTON,
                       tOptionsTemp.bAutofiletypeAllowed);
} /* end of vChangeAutofiletype */

/*
* vChangeHiddenText - invert the hide/show hidden text
*/
static void
vChangeHiddenText(window_handle tWindow)
{
       tOptionsTemp.bHideHiddenText = !tOptionsTemp.bHideHiddenText;
       vUpdateRadioButton(tWindow,
                       CHOICES_HIDDEN_TEXT_BUTTON,
                       tOptionsTemp.bHideHiddenText);
} /* end of vChangeHiddenText */

/*
* vUseFontsImages - use outline fonts, show images
*/
static void
vUseFontsImages(BOOL bUseOutlineFonts, BOOL bShowImages)
{
       tOptionsTemp.eConversionType =
               bUseOutlineFonts ? conversion_draw : conversion_text;
       tOptionsTemp.eImageLevel =
               bUseOutlineFonts && bShowImages ?
               level_default : level_no_images;
} /* end of vUseFontsImages */

/*
* vSetScaleFactor - set the scale factor to the given number
*/
static void
vSetScaleFactor(window_handle tWindow, int iNumber)
{
       tOptionsTemp.iScaleFactor = iNumber;
       vUpdateWriteableNumber(tWindow,
                       CHOICES_SCALE_WRITEABLE,
                       tOptionsTemp.iScaleFactor);
} /* end of vSetScaleFactor */

/*
* vChangeScaleFactor - change the scale factor with the given number
*/
static void
vChangeScaleFactor(window_handle tWindow, int iNumber)
{
       int     iTmp;

       iTmp = tOptionsTemp.iScaleFactor + iNumber;
       if (iTmp < MIN_SCALE_FACTOR || iTmp > MAX_SCALE_FACTOR) {
               /* Ignore */
               return;
       }
       tOptionsTemp.iScaleFactor = iTmp;
       vUpdateWriteableNumber(tWindow,
                       CHOICES_SCALE_WRITEABLE,
                       tOptionsTemp.iScaleFactor);
} /* end of vChangeScaleFactor */

/*
* bChoicesMouseClick - handle a mouse click in the Choices window
*/
BOOL
bChoicesMouseClick(event_pollblock *pEvent, void *pvReference)
{
       icon_handle     tAction;
       mouse_block     *pMouse;
       BOOL            bCloseWindow;

       TRACE_MSG("bChoicesMouseClick");

       fail(pEvent == NULL);
       fail(pEvent->type != event_CLICK);

       pMouse = &pEvent->data.mouse;
       if (!pMouse->button.data.select && !pMouse->button.data.adjust) {
               /* Not handled here */
               DBG_HEX(pMouse->button.value);
               return FALSE;
       }

       /* Which action should be taken */
       tAction = pMouse->icon;
       if (pMouse->button.data.adjust) {
               /* The adjust button reverses the direction */
               switch (pMouse->icon) {
               case CHOICES_BREAK_UP_BUTTON:
                       tAction = CHOICES_BREAK_DOWN_BUTTON;
                       break;
               case CHOICES_BREAK_DOWN_BUTTON:
                       tAction = CHOICES_BREAK_UP_BUTTON;
                       break;
               case CHOICES_SCALE_UP_BUTTON:
                       tAction = CHOICES_SCALE_DOWN_BUTTON;
                       break;
               case CHOICES_SCALE_DOWN_BUTTON:
                       tAction = CHOICES_SCALE_UP_BUTTON;
                       break;
               default:
                       break;
               }
       }

       /* Actions */
       bCloseWindow = FALSE;
       switch (tAction) {
       case CHOICES_DEFAULT_BUTTON:
               vDefaultButtonAction(pMouse->window);
               break;
       case CHOICES_SAVE_BUTTON:
               vSaveButtonAction();
               break;
       case CHOICES_CANCEL_BUTTON:
               bCloseWindow = TRUE;
               break;
       case CHOICES_APPLY_BUTTON:
               vApplyButtonAction();
               bCloseWindow = TRUE;
               break;
       case CHOICES_BREAK_BUTTON:
               vSetParagraphBreak(pMouse->window, DEFAULT_SCREEN_WIDTH);
               break;
       case CHOICES_BREAK_UP_BUTTON:
               vChangeParagraphBreak(pMouse->window, 1);
               break;
       case CHOICES_BREAK_DOWN_BUTTON:
               vChangeParagraphBreak(pMouse->window, -1);
               break;
       case CHOICES_NO_BREAK_BUTTON:
               vSetParagraphBreak(pMouse->window, 0);
               break;
       case CHOICES_AUTOFILETYPE_BUTTON:
               vChangeAutofiletype(pMouse->window);
               break;
       case CHOICES_HIDDEN_TEXT_BUTTON:
               vChangeHiddenText(pMouse->window);
               break;
       case CHOICES_WITH_IMAGES_BUTTON:
               vUseFontsImages(TRUE, TRUE);
               break;
       case CHOICES_NO_IMAGES_BUTTON:
               vUseFontsImages(TRUE, FALSE);
               break;
       case CHOICES_TEXTONLY_BUTTON:
               vUseFontsImages(FALSE, FALSE);
               break;
       case CHOICES_SCALE_UP_BUTTON:
               vChangeScaleFactor(pMouse->window, 5);
               break;
       case CHOICES_SCALE_DOWN_BUTTON:
               vChangeScaleFactor(pMouse->window, -5);
               break;
       default:
               DBG_DEC(pMouse->icon);
               break;
       }
       if (bCloseWindow) {
               Error_CheckFatal(Wimp_CloseWindow(pMouse->window));
       }
       return TRUE;
} /* end of bChoicesMouseClick */

/*
* bChoicesKeyPressed - handle a key in the Choices window
*/
BOOL
bChoicesKeyPressed(event_pollblock *pEvent, void *pvReference)
{
       icon_block      tIcon;
       caret_block     *pCaret;
       char            *pcChar;
       int             iNumber;

       DBG_MSG("bChoicesKeyPressed");

       fail(pEvent == NULL);
       fail(pEvent->type != event_KEY);

       if (pEvent->data.key.code != '\r') {
               Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
               return TRUE;
       }

       pCaret = &pEvent->data.key.caret;

       Error_CheckFatal(Wimp_GetIconState(pCaret->window, pCaret->icon, &tIcon));
       if (!tIcon.flags.data.text || !tIcon.flags.data.indirected) {
               werr(1, "Icon %d must be indirected text", (int)pCaret->icon);
       }
       iNumber = (int)strtol(tIcon.data.indirecttext.buffer, &pcChar, 10);

       switch(pCaret->icon) {
       case CHOICES_BREAK_WRITEABLE:
               if (*pcChar != '\0' && *pcChar != '\r') {
                       DBG_DEC(*pcChar);
                       iNumber = DEFAULT_SCREEN_WIDTH;
               } else if (iNumber < MIN_SCREEN_WIDTH) {
                       iNumber = MIN_SCREEN_WIDTH;
               } else if (iNumber > MAX_SCREEN_WIDTH) {
                       iNumber = MAX_SCREEN_WIDTH;
               }
               vSetParagraphBreak(pCaret->window, iNumber);
               break;
       case CHOICES_SCALE_WRITEABLE:
               if (*pcChar != '\0' && *pcChar != '\r') {
                       DBG_DEC(*pcChar);
                       iNumber = DEFAULT_SCALE_FACTOR;
               } else if (iNumber < MIN_SCALE_FACTOR) {
                       iNumber = MIN_SCALE_FACTOR;
               } else if (iNumber > MAX_SCALE_FACTOR) {
                       iNumber = MAX_SCALE_FACTOR;
               }
               vSetScaleFactor(pCaret->window, iNumber);
               break;
       default:
               DBG_DEC(pCaret->icon);
               break;
       }
       return TRUE;
} /* end of bChoicesKeyPressed */
#endif /* __riscos */