home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / w32misc.c < prev    next >
C/C++ Source or Header  |  1998-09-23  |  19KB  |  719 lines

  1. /*
  2.  * w32misc:  collection of unrelated, common win32 functions used by both
  3.  *           the console and GUI flavors of the editor.
  4.  *
  5.  * Caveats
  6.  * =======
  7.  * -- This code has not been tested with NT 3.51 .
  8.  *
  9.  * $Header: /usr/build/vile/vile/RCS/w32misc.c,v 1.10 1998/09/23 22:21:14 tom Exp $
  10.  */
  11.  
  12. #include <windows.h>
  13. #include <io.h>
  14. #include <conio.h>
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <errno.h>
  18. #include <process.h>
  19.  
  20. #include "estruct.h"
  21. #include "edef.h"
  22. #include "nefunc.h"
  23.  
  24. #define CSHEXE      "csh.exe"
  25. #define CSHEXE_LEN  (sizeof(CSHEXE) - 1)
  26. #define HOST_95     0
  27. #define HOST_NT     1
  28. #define HOST_UNDEF  (-1)
  29. #define SHEXE       "sh.exe"
  30. #define SHEXE_LEN   (sizeof(SHEXE) - 1)
  31. #define SHELL_C_LEN (sizeof(" -c ") - 1)
  32.  
  33. static int   host_type = HOST_UNDEF; /* nt or 95? */
  34. #ifndef DISP_NTWIN
  35. static char  saved_title[256];
  36. #endif
  37.  
  38. /* ------------------------------------------------------------------ */
  39.  
  40. #if DISP_NTWIN
  41. int
  42. stdin_data_available(void)
  43. {
  44.     FILE *fp;
  45.     int  rc = 0;
  46.  
  47.     if ((fp = fdopen(dup(fileno(stdin)), "r")) != NULL)
  48.     {
  49.         fclose(fp);
  50.         rc = 1;
  51.     }
  52.     return (rc);
  53. }
  54. #endif
  55.  
  56.  
  57. static void
  58. set_host(void)
  59. {
  60.     OSVERSIONINFO info;
  61.  
  62.     info.dwOSVersionInfoSize = sizeof(info);
  63.     GetVersionEx(&info);
  64.     host_type = (info.dwPlatformId == VER_PLATFORM_WIN32_NT) ?
  65.                 HOST_NT : HOST_95;
  66. }
  67.  
  68.  
  69.  
  70. int
  71. is_winnt(void)
  72. {
  73.     if (host_type == HOST_UNDEF)
  74.         set_host();
  75.     return (host_type == HOST_NT);
  76. }
  77.  
  78.  
  79.  
  80. int
  81. is_win95(void)
  82. {
  83.     if (host_type == HOST_UNDEF)
  84.         set_host();
  85.     return (host_type == HOST_95);
  86. }
  87.  
  88.  
  89.  
  90. /*
  91.  * FUNCTION
  92.  *   mk_shell_cmd_str(char *cmd, int *allocd_mem, int prepend_shc)
  93.  *
  94.  *   cmd         - command string to be be passed to a Win32 command
  95.  *                 interpreter.
  96.  *
  97.  *   alloced_mem - Boolean, T -> returned string was allocated on heap.
  98.  *
  99.  *   prepend_shc - Boolean, T -> prepend "$SHELL -c" to cmd.
  100.  *
  101.  * DESCRIPTION
  102.  *   If the user's shell is a unix lookalike, then a command passed to
  103.  *   system() or CreateProcess() requires special preprocessing.
  104.  *   This extra processing is required because the aforementioned
  105.  *   functions pass a "raw", flat command line to the shell that is
  106.  *   _not_ broken up into the following four canonical argv components:
  107.  *
  108.  *     argv[0] = name of shell
  109.  *     argv[1] = name of shell
  110.  *     argv[2] = -c
  111.  *     argv[3] = cmd
  112.  *     argv[4] = NULL
  113.  *
  114.  *   Put another way, a true execlp() does not exist in the win32 world and,
  115.  *   therefore, cannnot be called to effect sh -c "cmdstr".  Consequently,
  116.  *   when a unix shell (executing under win32) receives a "raw" command line,
  117.  *   the shell splits the raw command into words, performs its normal
  118.  *   expansions (file globbing, variable substitution, etc.) and then
  119.  *   removes all quote characters.  After that, the shell executes the
  120.  *   command.  This scenario means that if the user tries the following
  121.  *   command in vile:
  122.  *
  123.  *       :!echo 'word1    word2'
  124.  *
  125.  *   It is passed to the shell as:
  126.  *
  127.  *        sh -c echo 'word1    word2'
  128.  *
  129.  *   and is displayed by the shell as:
  130.  *
  131.  *        word1 word2
  132.  *
  133.  *   That's not a big deal, but consider this vile idiom:
  134.  *
  135.  *        ^X-!egrep -n 'word1 word2' *.c
  136.  *
  137.  *   Egrep receives the following command line from the shell:
  138.  *
  139.  *        egrep -n word1 word2 <glob'd file list>
  140.  *
  141.  *   Oops.  Word2 of the regular expression is now a filename.
  142.  *
  143.  * SOLUTIONS
  144.  *   1) If user's shell is a unix lookalike and the command contains no
  145.  *      single quote delimiters, enclose the entire command in single
  146.  *      quotes.  This forces the shell to treat the command string
  147.  *      as a single argument _before_ word splitting, expansions, and
  148.  *      quote removal.  Otherwise,
  149.  *
  150.  *   2) If user's shell is a unix lookalike, enclose the command string in
  151.  *      double quotes and escape every nonquoted double quote within the
  152.  *      original string.  This is the same principle as 1) above, but uses
  153.  *      a nestable delimiter.  This solution isn't foolproof.  Consider:
  154.  *
  155.  *          ^X-!echo '[#@$*]' \"special\" word
  156.  *
  157.  *      will be read into the error buffer as:
  158.  *
  159.  *          [#@$*] special word
  160.  *
  161.  *      This could be worked around by preceding a leading \" token with '
  162.  *      and appending ' to its closing delimiter.  But that creates its
  163.  *      own set of side effects.
  164.  *
  165.  * CAVEATS
  166.  *   The workarounds are inappropriate for csh (variants) which don't
  167.  *   support nested quotes.
  168.  *
  169.  * RETURNS
  170.  *   Pointer to possibly modified string.  If modified, the command string
  171.  *   was created on the heap and must be free'd by the client.  If
  172.  *   storage can't be allocated, NULL is returned.
  173.  */
  174.  
  175. char *
  176. mk_shell_cmd_str(char *cmd, int *allocd_mem, int prepend_shc)
  177. {
  178.     int         alloc_len;
  179.     static int  bourne_shell = 0; /* Boolean, T if user's shell has
  180.                                    * appearances of a Unix lookalike
  181.                                    * bourne shell (e.g., sh, ksh, bash).
  182.                                    */
  183.     char        *out_str, *cp;
  184.     static char *shell = NULL, *shell_c = "/c";
  185.  
  186.     if (shell == NULL)
  187.     {
  188.         int len;
  189.  
  190.         shell        = get_shell();
  191.         len          = strlen(shell);
  192.         bourne_shell = (len >= 2 &&
  193.                         tolower(shell[len - 2]) == 's' &&
  194.                         tolower(shell[len - 1]) == 'h')
  195.                                ||
  196.                        (len >= SHEXE_LEN &&
  197.                         stricmp(shell + len - SHEXE_LEN, SHEXE) == 0);
  198.         if (bourne_shell)
  199.         {
  200.             shell_c = "-c";
  201.  
  202.             /* Now check for csh lookalike. */
  203.             bourne_shell = ! (
  204.                                (len >= 3 &&
  205.                                tolower(shell[len - 3]) == 'c')
  206.                                         ||
  207.                                (len >= CSHEXE_LEN &&
  208.                                 stricmp(shell + len - CSHEXE_LEN, CSHEXE) == 0)
  209.                              );
  210.         }
  211.     }
  212.     if (! bourne_shell)
  213.     {
  214.         /*
  215.          * MS-DOS shell or csh.  Do not bother quoting user's command
  216.          * string, since the former is oblivious to the notion of a unix
  217.          * shell's argument quoting and the latter does not support nested
  218.          * double quotes.
  219.          */
  220.  
  221.         if (prepend_shc)
  222.         {
  223.             alloc_len = strlen(cmd) + strlen(shell) + SHELL_C_LEN + 1;
  224.             if ((out_str = malloc(alloc_len)) == NULL)
  225.                 return (out_str);
  226.             *allocd_mem = TRUE;
  227.             sprintf(out_str, "%s %s %s", shell, shell_c, cmd);
  228.             return (out_str);
  229.         }
  230.         else
  231.         {
  232.             *allocd_mem = FALSE;
  233.             return (cmd);
  234.         }
  235.     }
  236.  
  237.     /* Else apply solutions 1-2 above. */
  238.     alloc_len = strlen(cmd) * 2; /* worst case -- every cmd byte quoted */
  239.     if (prepend_shc)
  240.         alloc_len += strlen(shell) + SHELL_C_LEN;
  241.     alloc_len += 3;              /* terminating nul + 2 quote chars     */
  242.     if ((out_str = malloc(alloc_len)) == NULL)
  243.     {
  244.         errno = ENOMEM;
  245.         return (out_str);
  246.     }
  247.     *allocd_mem = TRUE;
  248.  
  249.     cp = out_str;
  250.     if (prepend_shc)
  251.         cp += sprintf(cp, "%s %s ", shell, shell_c);
  252.     if (strchr(cmd, '\'') == NULL)
  253.     {
  254.         /* No single quotes in command string.  Solution #1. */
  255.  
  256.         sprintf(cp, "'%s'", cmd);
  257.         return (out_str);
  258.     }
  259.  
  260.     /* Solution #2. */
  261.     *cp++ = '"';
  262.     while (*cmd)
  263.     {
  264.         if (*cmd == '\\')
  265.         {
  266.             *cp++ = *cmd++;
  267.             if (*cmd)
  268.             {
  269.                 /* Any quoted char is immune to further quoting. */
  270.  
  271.                 *cp++ = *cmd++;
  272.             }
  273.         }
  274.         else if (*cmd != '"')
  275.             *cp++ = *cmd++;
  276.         else
  277.         {
  278.             /* bare '"' */
  279.  
  280.             *cp++ = '\\';
  281.             *cp++ = *cmd++;
  282.         }
  283.     }
  284.     *cp++ = '"';
  285.     *cp   = '\0';
  286.     return (out_str);
  287. }
  288.  
  289.  
  290.  
  291. /*
  292.  * FUNCTION
  293.  *   w32_system(const char *cmd)
  294.  *
  295.  *   cmd - command string to be be passed to a Win32 command interpreter.
  296.  *
  297.  * DESCRIPTION
  298.  *   Executes a system() call, taking care to ensure that the user's
  299.  *   command string is properly quoted if get_shell() points to a bourne
  300.  *   shell clone.
  301.  *
  302.  * RETURNS
  303.  *   If memory allocation fails, -1.
  304.  *   Else, whatever system() returns.
  305.  */
  306.  
  307. int
  308. w32_system(const char *cmd)
  309. {
  310.     char *cmdstr;
  311.     int  freestr, rc;
  312.  
  313.     if ((cmdstr = mk_shell_cmd_str((char *) cmd, &freestr, FALSE)) == NULL)
  314.     {
  315.         /* heap exhausted! */
  316.  
  317.         (void) no_memory("w32_system()");
  318.         return (-1);
  319.     }
  320.     set_console_title(cmd);
  321.     rc = system(cmdstr);
  322.     if (freestr)
  323.         free(cmdstr);
  324.     restore_console_title();
  325.     return (rc);
  326. }
  327.  
  328.  
  329.  
  330. #if DISP_NTWIN
  331. /*
  332.  * FUNCTION
  333.  *   w32_system_winvile(const char *cmd)
  334.  *
  335.  *   cmd - command string to be be passed to a Win32 command interpreter.
  336.  *
  337.  * DESCRIPTION
  338.  *   Executes a system() call in the context of a Win32 GUI application,
  339.  *   taking care to ensure that the user's command string is properly
  340.  *   quoted if get_shell() points to a bourne shell clone.
  341.  *
  342.  *   "In the context of a Win32 GUI application" means that:
  343.  *
  344.  *   a) the GUI requires explicit console allocation prior to exec'ing
  345.  *      "cmd", and
  346.  *   b) said console stays "up" until explicitly dismissed by the user.
  347.  *
  348.  * ACKNOWLEDGMENTS
  349.  *   I had no idea a Win32 GUI app could exec a console command until I
  350.  *   browsed the win32 gvim code.
  351.  *
  352.  * RETURNS
  353.  *   If memory/console allocation fails, -1.
  354.  *   Else whatever the executed command returns.
  355.  */
  356.  
  357. int
  358. w32_system_winvile(const char *cmd)
  359. {
  360. #define PRESS_ANY_KEY "\n[Press any key to continue]"
  361.  
  362.     char                 *cmdstr;
  363.     int                  freestr, rc = -1;
  364.     PROCESS_INFORMATION  pi;
  365.     STARTUPINFO          si;
  366.  
  367.     if ((cmdstr = mk_shell_cmd_str((char *) cmd, &freestr, TRUE)) == NULL)
  368.     {
  369.         /* heap exhausted! */
  370.  
  371.         (void) no_memory("w32_system_winvile()");
  372.         return (rc);
  373.     }
  374.     if (! AllocConsole())
  375.     {
  376.         if (freestr)
  377.             free(cmdstr);
  378.         mlforce("console creation failed");
  379.         return (rc);
  380.     }
  381.     SetConsoleTitle(cmd);
  382.     memset(&si, 0, sizeof(si));
  383.     si.cb          = sizeof(si);
  384.     si.dwFlags     = STARTF_USESTDHANDLES;
  385.     si.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
  386.     si.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
  387.     si.hStdError   = GetStdHandle(STD_ERROR_HANDLE);
  388.     if (CreateProcess(NULL,
  389.                       cmdstr,
  390.                       NULL,
  391.                       NULL,
  392.                       TRUE,       /* Inherit handles */
  393.                       0,
  394.                       NULL,
  395.                       NULL,
  396.                       &si,
  397.                       &pi))
  398.     {
  399.         /* Success */
  400.  
  401.         DWORD        dummy;
  402.         INPUT_RECORD ir;
  403.  
  404.         (void) _cwait(&rc, (int) pi.hProcess, 0);
  405.         (void) WriteFile(si.hStdOutput,
  406.                          PRESS_ANY_KEY,
  407.                          sizeof(PRESS_ANY_KEY) - 1,
  408.                          &dummy,
  409.                          NULL);
  410.         for (;;)
  411.         {
  412.             /* Wait for a single key of input from user. */
  413.  
  414.             if (! ReadConsoleInput(si.hStdInput, &ir, 1, &dummy))
  415.                 break;      /* What?? */
  416.             if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
  417.                 break;
  418.         }
  419.         (void) CloseHandle(pi.hProcess);
  420.         (void) CloseHandle(pi.hThread);
  421.     }
  422.     else
  423.     {
  424.         /* Bummer */
  425.  
  426.         mlforce("unable to exec console command");
  427.     }
  428.     if (freestr)
  429.         free(cmdstr);
  430.     FreeConsole();
  431.     return (rc);
  432. }
  433. #endif /* DISP_NTWIN */
  434.  
  435.  
  436.  
  437. /*
  438.  * FUNCTION
  439.  *   w32_keybrd_reopen(int pressret)
  440.  *
  441.  *   pressret - Boolean, T -> display prompt and wait for response
  442.  *
  443.  * DESCRIPTION
  444.  *   This is essentially the Win32 equivalent of the pressreturn() function
  445.  *   in spawn.c, but differs in that it reopens the console keyboard _after_
  446.  *   prompting the user to press return.  Order is important IF the user has
  447.  *   configured his/her dos box such that the buffer size exceeds the
  448.  *   window size.  In that scenario, if the ntconio.c routines gained
  449.  *   control (via TTkopen) before the prompt, then the output of the
  450.  *   previous shell command (e.g., :!dir) is immediately thrown away
  451.  *   due to a screen context switch and the user has no chance to read the
  452.  *   shell output.
  453.  *
  454.  *   This function prevents that scenario from occurring.
  455.  *
  456.  * APPLIES TO
  457.  *   W32 console vile only.
  458.  *
  459.  * RETURNS
  460.  *   None
  461.  */
  462.  
  463. void
  464. w32_keybrd_reopen(int pressret)
  465. {
  466. #ifdef DISP_NTCONS
  467.     int c;
  468.  
  469.     if (pressret)
  470.     {
  471.         fputs("[Press return to continue]", stdout);
  472.         fflush(stdout);
  473.  
  474.         /* loop for a CR, a space, or a : to do another named command */
  475.         while ((c = _getch()) != '\r' &&
  476.                 c != '\n' &&
  477.                 c != ' ' &&
  478.                 !ABORTED(c))
  479.         {
  480.             if (kcod2fnc(c) == &f_namedcmd)
  481.             {
  482.                 unkeystroke(c);
  483.                 break;
  484.             }
  485.         }
  486.     }
  487.     TTkopen();
  488.     kbd_erase_to_end(0);
  489. #endif
  490. }
  491.  
  492.  
  493.  
  494. /*
  495.  * The code in ntconio.c that saves and restores console titles
  496.  * didn't work reliably for pipe or shell operations.  It's moved here
  497.  * now and called via the w32_system() wrapper or the w32pipe module.
  498.  */
  499. void
  500. set_console_title(const char *title)
  501. {
  502. #ifndef DISP_NTWIN
  503.     GetConsoleTitle(saved_title, sizeof(saved_title));
  504.     SetConsoleTitle(title);
  505. #endif
  506. }
  507.  
  508.  
  509.  
  510. void
  511. restore_console_title(void)
  512. {
  513. #ifndef DISP_NTWIN
  514.     SetConsoleTitle(saved_title);
  515. #endif
  516. }
  517.  
  518.  
  519.  
  520. /*
  521.  * FUNCTION
  522.  *   fmt_win32_error(ULONG errcode, char **buf, ULONG buflen)
  523.  *
  524.  *   errcode - win32 error code for which message applies.  If errcode is
  525.  *             W32_SYS_ERROR, GetLastError() will be invoked to obtain the
  526.  *             error code.
  527.  *
  528.  *   buf     - indirect pointer to buf to receive formatted message.  If *buf
  529.  *             is NULL, the buffer is allocated on behalf of the client and
  530.  *             must be free'd using LocalFree().
  531.  *
  532.  *   buflen  - length of buffer (specify 0 if *buf is NULL).
  533.  *
  534.  * DESCRIPTION
  535.  *   Format system error reported by Win32 API.
  536.  *
  537.  * RETURNS
  538.  *   *buf
  539.  */
  540.  
  541. char *
  542. fmt_win32_error(ULONG errcode, char **buf, ULONG buflen)
  543. {
  544.     int flags = FORMAT_MESSAGE_FROM_SYSTEM;
  545.  
  546.     if (! *buf)
  547.         flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  548.     FormatMessage(flags,
  549.                   NULL,
  550.                   errcode == W32_SYS_ERROR ? GetLastError() : errcode,
  551.                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* dflt language */
  552.                   (*buf) ? *buf : (LPTSTR) buf,
  553.                   buflen,
  554.                   NULL);
  555.     return (*buf);
  556. }
  557.  
  558.  
  559.  
  560. /*
  561.  * FUNCTION
  562.  *   disp_win32_error(ULONG errcode, void *hwnd)
  563.  *
  564.  *   errcode - win32 error code for which message applies.  If errcode is
  565.  *             W32_SYS_ERROR, GetLastError() will be invoked to obtain the
  566.  *             error code.
  567.  *
  568.  *   hwnd    - specifies the window handle argument to MessageBox (can be NULL).
  569.  *
  570.  * DESCRIPTION
  571.  *   Format system error reported by Win32 API and display in message box.
  572.  *
  573.  * RETURNS
  574.  *   None
  575.  */
  576.  
  577. void
  578. disp_win32_error(ULONG errcode, void *hwnd)
  579. {
  580.     char *buf = NULL;
  581.  
  582.     fmt_win32_error(errcode, &buf, 0);
  583.     MessageBox(hwnd, buf, prognam, MB_OK|MB_ICONSTOP);
  584.     LocalFree(buf);
  585. }
  586.  
  587.  
  588.  
  589. #if DISP_NTWIN
  590. /*
  591.  * FUNCTION
  592.  *   parse_font_str(const char *fontstr, FONTSTR_OPTIONS *results)
  593.  *
  594.  *   fontstr - a font specification string, see DESCRIPTION below.
  595.  *
  596.  *   results - Pointer to structure that returns data from a successfully
  597.  *             parsed font string.
  598.  *
  599.  * DESCRIPTION
  600.  *   Turns a font specification string into a LOGFONT data structure.
  601.  *   Specification syntax is as follows:
  602.  *
  603.  *     <font>  :== [<face>,]<size>[,<style>]
  604.  *
  605.  *     <face>  :== font-name
  606.  *     <size>  :== point size (integer)
  607.  *     <style> :== { bold | italic | bold-italic }
  608.  *
  609.  *     ex:    Letter Gothic,8
  610.  *     ex:    r_ansi,8,bold
  611.  *
  612.  *     Note 1:  If <style> unspecified, "normal" is assumed.
  613.  *     Note 2:  if <face> contains a comma it should be escaped with '\'.
  614.  *     Note 3:  if <face> is omitted, the current font is modified.
  615.  *
  616.  * RETURNS
  617.  *   Boolean, T -> font syntax ok, else bogus syntax
  618.  */
  619.  
  620. int
  621. parse_font_str(const char *fontstr, FONTSTR_OPTIONS *results)
  622. {
  623.     const char    *cp, *tmp;
  624.     char          *endnum, *facep;
  625.     unsigned long size;
  626.  
  627.     memset(results, 0, sizeof(*results));
  628.     size  = 0;
  629.     cp    = fontstr;
  630.     while (*cp && isspace(*cp))
  631.         cp++;
  632.  
  633.     /* Up first is either a font face or font size. */
  634.     if (isdigit(*cp))
  635.     {
  636.         errno = 0;
  637.         size  = strtoul(cp, &endnum, 10);
  638.         if (errno != 0)
  639.             return (FALSE);
  640.         tmp = endnum;
  641.         while (*tmp && isspace(*tmp))
  642.             tmp++;
  643.         if (*tmp != '\0')
  644.         {
  645.             if (*tmp != ',')
  646.             {
  647.                 /* Not a 100% integer value, assume this is a font face. */
  648.  
  649.                 size = 0;
  650.             }
  651.             else
  652.                 cp = tmp;      /* Valid point size. */
  653.         }
  654.         else
  655.             cp = tmp;         /* Only a point size specified, nothing left. */
  656.     }
  657.     if (size == 0)
  658.     {
  659.         /* this must be a font face */
  660.  
  661.         facep = results->face;
  662.         while (*cp)
  663.         {
  664.             if (*cp == ',')
  665.             {
  666.                 cp++;
  667.                 break;
  668.             }
  669.             else if (*cp == '\\' && cp[1] == ',')
  670.             {
  671.                 *facep++  = ',';
  672.                 cp       += 2;
  673.             }
  674.             else
  675.                 *facep++ = *cp++;
  676.         }
  677.         *facep = '\0';
  678.         if (results->face[0] == '\0' || *cp == '\0')
  679.             return (FALSE);
  680.         else
  681.         {
  682.             /* Now pick up non-optional font size (that follows face). */
  683.  
  684.             errno = 0;
  685.             size  = strtoul(cp, &endnum, 10);
  686.             if (errno != 0 || size == 0)
  687.                 return (FALSE);
  688.             cp = endnum;
  689.         }
  690.     }
  691.  
  692.     /* Now look for optional font style. */
  693.     while (*cp && isspace(*cp))
  694.         cp++;
  695.  
  696.     /* At this point, there are two allowable states:  delimiter or EOS. */
  697.     if (*cp)
  698.     {
  699.         if (*cp++ == ',')
  700.         {
  701.             while (*cp && isspace(*cp))
  702.                 cp++;
  703.             if (strncmp(cp, "bold-italic", sizeof("bold-italic") - 1) == 0)
  704.                 results->bold = results->italic = TRUE;
  705.             else if (strncmp(cp, "italic", sizeof("italic") - 1) == 0)
  706.                 results->italic = TRUE;
  707.             else if (strncmp(cp, "bold", sizeof("bold") - 1) == 0)
  708.                 results->bold = TRUE;
  709.             else
  710.                 return (FALSE);
  711.         }
  712.         else
  713.             return (FALSE);
  714.     }
  715.     results->size = size;
  716.     return (TRUE);
  717. }
  718. #endif  /* DISP_NTWIN */
  719.