ShowInfo()
{
  char buf[512], *p;
  register struct win *wp = fore;
  register int i;

  if (wp == 0)
    {
      Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height);
      return;
    }
  p = buf;
  if (buf < (p += GetAnsiStatus(wp, p)))
    *p++ = ' ';
  sprintf(p, "(%d,%d)/(%d,%d)",
    wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height);
#ifdef COPY_PASTE
  sprintf(p += strlen(p), "+%d", wp->w_histheight);
#endif
  sprintf(p += strlen(p), " %c%sflow",
  	  (wp->w_flow & FLOW_NOW) ? '+' : '-',
	  (wp->w_flow & FLOW_AUTOFLAG) ? "" :
	   ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)"));
  if (!wp->w_wrap) sprintf(p += strlen(p), " -wrap");
  if (wp->w_insert) sprintf(p += strlen(p), " ins");
  if (wp->w_origin) sprintf(p += strlen(p), " org");
  if (wp->w_keypad) sprintf(p += strlen(p), " app");
  if (wp->w_log)    sprintf(p += strlen(p), " log");
  if (wp->w_monitor != MON_OFF
#ifdef MULTIUSER
      && (ACLBYTE(wp->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))
#endif
     )
    sprintf(p += strlen(p), " mon");
  if (wp->w_mouse) sprintf(p += strlen(p), " mouse");
#ifdef COLOR
  if (wp->w_bce) sprintf(p += strlen(p), " bce");
#endif
  if (!wp->w_c1) sprintf(p += strlen(p), " -c1");
  if (wp->w_norefresh) sprintf(p += strlen(p), " nored");

  p += strlen(p);
#ifdef FONT
# ifdef ENCODINGS
  if (wp->w_encoding && (display == 0 || D_encoding != wp->w_encoding || EncodingDefFont(wp->w_encoding) <= 0))
    {
      *p++ = ' ';
      strcpy(p, EncodingName(wp->w_encoding));
      p += strlen(p);
    }
#  ifdef UTF8
  if (wp->w_encoding != UTF8)
#  endif
# endif
    if (display && (D_CC0 || (D_CS0 && *D_CS0)))
      {
	if (wp->w_gr == 2)
	  {
	    sprintf(p, " G%c", wp->w_Charset + '0');
	    if (wp->w_FontE >= ' ')
	      p[3] = wp->w_FontE;
	    else
	      {
	        p[3] = '^';
	        p[4] = wp->w_FontE ^ 0x40;
		p++;
	      }
	    p[4] = '[';
	    p++;
	  }
	else if (wp->w_gr)
	  sprintf(p++, " G%c%c[", wp->w_Charset + '0', wp->w_CharsetR + '0');
	else
	  sprintf(p, " G%c[", wp->w_Charset + '0');
	p += 4;
	for (i = 0; i < 4; i++)
	  {
	    if (wp->w_charsets[i] == ASCII)
	      *p++ = 'B';
	    else if (wp->w_charsets[i] >= ' ')
	      *p++ = wp->w_charsets[i];
	    else
	      {
		*p++ = '^';
		*p++ = wp->w_charsets[i] ^ 0x40;
	      }
	  }
	*p++ = ']';
	*p = 0;
      }
#endif

  if (wp->w_type == W_TYPE_PLAIN)
    {
      /* add info about modem control lines */
      *p++ = ' ';
      TtyGetModemStatus(wp->w_ptyfd, p);
    }
#ifdef BUILTIN_TELNET
  else if (wp->w_type == W_TYPE_TELNET)
    {
      *p++ = ' ';
      TelStatus(wp, p, sizeof(buf) - 1 - (p - buf));
    }
#endif
  Msg(0, "%s %d(%s)", buf, wp->w_number, wp->w_title);
}


ExtMouseMode(mode)
     int mode;
{
  if (display && D_extmouse != mode)
    {
      char mousebuf[20];
      if (!D_CXT)
        return;
      if (D_extmouse)
        {
          sprintf(mousebuf, "\033[?%dl", D_extmouse);
          AddStr(mousebuf);
        }
      if (mode)
        {
          sprintf(mousebuf, "\033[?%dh", mode);
          AddStr(mousebuf);
        }
      D_extmouse = mode;
      D_mouse_parse.state = CSI_INACTIVE;
    }
}


DeleteChar(n)
int n;
{
  register int y = curr->w_y, x = curr->w_x;

  if (x == cols)
    x--;
  save_mline(&curr->w_mlines[y], cols);
  MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
  LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
  LGotoPos(&curr->w_layer, x, y);
}


InputSetenv(arg)
char *arg;
{
  static char setenv_buf[50 + sizeof(setenv_var)];	/* need to be static here, cannot be freed */

  if (arg)
    {
      strncpy(setenv_var, arg, sizeof(setenv_var) - 1);
      sprintf(setenv_buf, "Enter value for %s: ", setenv_var);
      Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL, 0);
    }
  else
    Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL, 0);
}


InitTerm(adapt)
int adapt;
{
  ASSERT(display);
  ASSERT(D_tcinited);
  D_top = D_bot = -1;
  AddCStr(D_IS);
  AddCStr(D_TI);
  /* Check for toggle */
  if (D_IM && strcmp(D_IM, D_EI))
    AddCStr(D_EI);
  D_insert = 0;
#ifdef MAPKEYS
  AddCStr(D_KS);
  AddCStr(D_CCS);
#else
  /* Check for toggle */
  if (D_KS && strcmp(D_KS, D_KE))
    AddCStr(D_KE);
  if (D_CCS && strcmp(D_CCS, D_CCE))
    AddCStr(D_CCE);
#endif
  D_keypad = 0;
  D_cursorkeys = 0;
  AddCStr(D_ME);
  AddCStr(D_EA);
  AddCStr(D_CE0);
  D_rend = mchar_null;
  D_atyp = 0;
  if (adapt == 0)
    ResizeDisplay(D_defwidth, D_defheight);
  ChangeScrollRegion(0, D_height - 1);
  D_x = D_y = 0;
  Flush(3);
  ClearAll();
  debug1("we %swant to adapt all our windows to the display\n",
	 (adapt) ? "" : "don't ");
  /* In case the size was changed by a init sequence */
  CheckScreenSize((adapt) ? 2 : 0);
}


copy_reg_fn(buf, len, data)
char *buf;
int len;
char *data;	/* dummy */
{
  struct plop *pp = plop_tab + (int)(unsigned char)*buf;

  if (len)
    {
      *buf = 0;
      return;
    }
  if (pp->buf)
    free(pp->buf);
  pp->buf = 0;
  pp->len = 0;
  if (D_user->u_plop.len)
    {
      if ((pp->buf = (char *)malloc(D_user->u_plop.len)) == NULL)
	{
	  Msg(0, "%s", strnomem);
	  return;
	}
      bcopy(D_user->u_plop.buf, pp->buf, D_user->u_plop.len);
    }
  pp->len = D_user->u_plop.len;
#ifdef ENCODINGS
  pp->enc = D_user->u_plop.enc;
#endif
  Msg(0, "Copied %d characters into register %c", D_user->u_plop.len, *buf);
}


StringStart(type)
enum string_t type;
{
  curr->w_StringType = type;
  curr->w_stringp = curr->w_string;
  curr->w_state = ASTR;
}


NextWindow()
{
  register struct win **pp;
  int n = fore ? fore->w_number : maxwin;
  struct win *group = fore ? fore->w_group : 0;

  for (pp = fore ? wtab + n + 1 : wtab; pp != wtab + n; pp++)
    {
      if (pp == wtab + maxwin)
	pp = wtab;
      if (*pp)
	{
	  if (!fore || group == (*pp)->w_group)
	    break;
	}
    }
  if (pp == wtab + n)
    return -1;
  return pp - wtab;
}


BlankResize(wi, he)
int wi, he;
{
  flayer->l_width = wi;
  flayer->l_height = he;
  return 0;
}


SetRenditionMline(ml, x)
struct mline *ml;
int x;
{
  if (!display)
    return;
#ifdef COLOR
  if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
    {
      struct mchar mc;
      copy_mline2mchar(&mc, ml, x);
      SetRendition(&mc);
      return;
    }
# ifdef COLORS16
  if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
    {
      int a = ml->attr[x];
      if ((ml->attr[x] & A_BFG) && D_MD)
	a |= A_BD;
      if ((ml->attr[x] & A_BBG) && D_MB)
	a |= A_BL;
      if (D_rend.attr != a)
        SetAttr(a);
    }
  else
# endif /* COLORS16 */
#endif /* COLOR */
    if (D_rend.attr != ml->attr[x])
    SetAttr(ml->attr[x]);
#ifdef COLOR
  if (D_rend.color != ml->color[x]
# ifdef COLORS256
      || D_rend.colorx != ml->colorx[x]
# endif
# ifdef COLORS16
      || D_col16change
# endif
    )
    {
      struct mchar mc;
      copy_mline2mchar(&mc, ml, x);
      SetColor(rend_getfg(&mc), rend_getbg(&mc));
    }
#endif
#ifdef FONT
  if (D_rend.font != ml->font[x])
    SetFont(ml->font[x]);
#ifdef UTF8
  if (D_encoding == UTF8)
    D_rend.fontx = ml->fontx[x];
#endif
#endif
}


WriteLP(x2, y2)
int x2, y2;
{
  struct mchar oldrend;

  ASSERT(display);
  ASSERT(D_lp_missing);
  oldrend = D_rend;
  debug2("WriteLP(%d,%d)\n", x2, y2);
#ifdef DW_CHARS
  if (D_lpchar.mbcs)
    {
      if (x2 > 0)
	x2--;
      else
	D_lpchar = mchar_blank;
    }
#endif
  /* Can't use PutChar */
  GotoPos(x2, y2);
  SetRendition(&D_lpchar);
  PUTCHAR(D_lpchar.image);
#ifdef DW_CHARS
  if (D_lpchar.mbcs)
    PUTCHAR(D_lpchar.mbcs);
#endif
  D_lp_missing = 0;
  SetRendition(&oldrend);
}


Return()
{
  if (curr->w_x == 0)
    return;
  curr->w_x = 0;
  LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}


IsOnDisplay(wi)
struct win *wi;
{
  struct canvas *cv;
  ASSERT(display);
  for (cv = D_cvlist; cv; cv = cv->c_next)
    if (Layer2Window(cv->c_layer) == wi)
      return 1;
  return 0;
}


MagickExport void XGetResourceInfo(const ImageInfo *image_info,
  XrmDatabase database,const char *client_name,XResourceInfo *resource_info)
{
  char
    *directory,
    *resource_value;

  extern const char
    BorderColor[],
    ForegroundColor[];

  /*
    Initialize resource info fields.
  */
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(resource_info != (XResourceInfo *) NULL);
  (void) memset(resource_info,0,sizeof(*resource_info));
  resource_info->resource_database=database;
  resource_info->image_info=(ImageInfo *) image_info;
  (void) SetImageInfoProgressMonitor(resource_info->image_info,
    XMagickProgressMonitor,(void *) NULL);
  resource_info->quantize_info=CloneQuantizeInfo((QuantizeInfo *) NULL);
  resource_info->close_server=MagickTrue;
  resource_info->client_name=AcquireString(client_name);
  resource_value=XGetResourceClass(database,client_name,"backdrop",
    (char *) "False");
  resource_info->backdrop=IsStringTrue(resource_value);
  resource_info->background_color=XGetResourceInstance(database,client_name,
    "background",(char *) "#d6d6d6d6d6d6");
  resource_info->border_color=XGetResourceInstance(database,client_name,
    "borderColor",BorderColor);
  resource_value=XGetResourceClass(database,client_name,"borderWidth",
    (char *) "2");
  resource_info->border_width=(unsigned int) StringToUnsignedLong(
    resource_value);
  resource_value=XGetResourceClass(database,client_name,"colormap",
    (char *) "shared");
  resource_info->colormap=UndefinedColormap;
  if (LocaleCompare("private",resource_value) == 0)
    resource_info->colormap=PrivateColormap;
  if (LocaleCompare("shared",resource_value) == 0)
    resource_info->colormap=SharedColormap;
  if (resource_info->colormap == UndefinedColormap)
    ThrowXWindowException(OptionError,"UnrecognizedColormapType",
      resource_value);
  resource_value=XGetResourceClass(database,client_name,
    "colorRecovery",(char *) "False");
  resource_info->color_recovery=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"confirmExit",
    (char *) "False");
  resource_info->confirm_exit=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"confirmEdit",
    (char *) "False");
  resource_info->confirm_edit=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"delay",(char *) "1");
  resource_info->delay=(unsigned int) StringToUnsignedLong(resource_value);
  resource_info->display_gamma=XGetResourceClass(database,client_name,
    "displayGamma",(char *) "2.2");
  resource_value=XGetResourceClass(database,client_name,"displayWarnings",
    (char *) "True");
  resource_info->display_warnings=IsStringTrue(resource_value);
  resource_info->font=XGetResourceClass(database,client_name,"font",
    (char *) NULL);
  resource_info->font=XGetResourceClass(database,client_name,"fontList",
    resource_info->font);
  resource_info->font_name[0]=XGetResourceClass(database,client_name,"font1",
    (char *) "fixed");
  resource_info->font_name[1]=XGetResourceClass(database,client_name,"font2",
    (char *) "variable");
  resource_info->font_name[2]=XGetResourceClass(database,client_name,"font3",
    (char *) "5x8");
  resource_info->font_name[3]=XGetResourceClass(database,client_name,"font4",
    (char *) "6x10");
  resource_info->font_name[4]=XGetResourceClass(database,client_name,"font5",
    (char *) "7x13bold");
  resource_info->font_name[5]=XGetResourceClass(database,client_name,"font6",
    (char *) "8x13bold");
  resource_info->font_name[6]=XGetResourceClass(database,client_name,"font7",
    (char *) "9x15bold");
  resource_info->font_name[7]=XGetResourceClass(database,client_name,"font8",
    (char *) "10x20");
  resource_info->font_name[8]=XGetResourceClass(database,client_name,"font9",
    (char *) "12x24");
  resource_info->font_name[9]=XGetResourceClass(database,client_name,"font0",
    (char *) "fixed");
  resource_info->font_name[10]=XGetResourceClass(database,client_name,"font0",
    (char *) "fixed");
  resource_info->foreground_color=XGetResourceInstance(database,client_name,
    "foreground",ForegroundColor);
  resource_value=XGetResourceClass(database,client_name,"gammaCorrect",
    (char *) "False");
  resource_info->gamma_correct=IsStringTrue(resource_value);
  resource_info->image_geometry=ConstantString(XGetResourceClass(database,
    client_name,"geometry",(char *) NULL));
  resource_value=XGetResourceClass(database,client_name,"gravity",
    (char *) "Center");
  resource_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
    MagickFalse,resource_value);
  directory=getcwd(resource_info->home_directory,MagickPathExtent);
  (void) directory;
  resource_info->icon_geometry=XGetResourceClass(database,client_name,
    "iconGeometry",(char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"iconic",
    (char *) "False");
  resource_info->iconic=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"immutable",
    LocaleCompare(client_name,"PerlMagick") == 0 ? (char *) "True" :
    (char *) "False");
  resource_info->immutable=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"magnify",
    (char *) "3");
  resource_info->magnify=(unsigned int) StringToUnsignedLong(resource_value);
  resource_info->map_type=XGetResourceClass(database,client_name,"map",
    (char *) NULL);
  resource_info->matte_color=XGetResourceInstance(database,client_name,
    "mattecolor",(char *) NULL);
  resource_info->name=ConstantString(XGetResourceClass(database,client_name,
    "name",(char *) NULL));
  resource_info->pen_colors[0]=XGetResourceClass(database,client_name,"pen1",
    (char *) "black");
  resource_info->pen_colors[1]=XGetResourceClass(database,client_name,"pen2",
    (char *) "blue");
  resource_info->pen_colors[2]=XGetResourceClass(database,client_name,"pen3",
    (char *) "cyan");
  resource_info->pen_colors[3]=XGetResourceClass(database,client_name,"pen4",
    (char *) "green");
  resource_info->pen_colors[4]=XGetResourceClass(database,client_name,"pen5",
    (char *) "gray");
  resource_info->pen_colors[5]=XGetResourceClass(database,client_name,"pen6",
    (char *) "red");
  resource_info->pen_colors[6]=XGetResourceClass(database,client_name,"pen7",
    (char *) "magenta");
  resource_info->pen_colors[7]=XGetResourceClass(database,client_name,"pen8",
    (char *) "yellow");
  resource_info->pen_colors[8]=XGetResourceClass(database,client_name,"pen9",
    (char *) "white");
  resource_info->pen_colors[9]=XGetResourceClass(database,client_name,"pen0",
    (char *) "gray");
  resource_info->pen_colors[10]=XGetResourceClass(database,client_name,"pen0",
    (char *) "gray");
  resource_value=XGetResourceClass(database,client_name,"pause",(char *) "0");
  resource_info->pause=(unsigned int) StringToUnsignedLong(resource_value);
  resource_value=XGetResourceClass(database,client_name,"quantum",(char *) "1");
  resource_info->quantum=StringToLong(resource_value);
  resource_info->text_font=XGetResourceClass(database,client_name,(char *)
    "font",(char *) "fixed");
  resource_info->text_font=XGetResourceClass(database,client_name,
    "textFontList",resource_info->text_font);
  resource_info->title=XGetResourceClass(database,client_name,"title",
    (char *) NULL);
  resource_value=XGetResourceClass(database,client_name,"undoCache",
    (char *) "256");
  resource_info->undo_cache=(unsigned int) StringToUnsignedLong(resource_value);
  resource_value=XGetResourceClass(database,client_name,"update",
    (char *) "False");
  resource_info->update=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"usePixmap",
    (char *) "True");
  resource_info->use_pixmap=IsStringTrue(resource_value);
  resource_value=XGetResourceClass(database,client_name,"sharedMemory",
    (char *) "True");
  resource_info->use_shared_memory=IsStringTrue(resource_value);
  resource_info->visual_type=XGetResourceClass(database,client_name,"visual",
    (char *) NULL);
  resource_info->window_group=XGetResourceClass(database,client_name,
    "windowGroup",(char *) NULL);
  resource_info->window_id=XGetResourceClass(database,client_name,"window",
    (char *) NULL);
  resource_info->write_filename=XGetResourceClass(database,client_name,
    "writeFilename",(char *) NULL);
}


MagickPrivate XFontStruct *XBestFont(Display *display,
  const XResourceInfo *resource_info,const MagickBooleanType text_font)
{
  static const char
    *Fonts[]=
    {
      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
      "-*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1",
      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-15",
      "-*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-15",
      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-*-*",
      "-*-arial-medium-r-normal--12-*-*-*-*-*-*-*",
      "variable",
      "fixed",
      (char *) NULL
    },
    *TextFonts[]=
    {
      "-*-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-1",
      "-*-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-15",
      "-*-fixed-medium-r-normal-*-12-*-*-*-*-*-*-*",
      "fixed",
      (char *) NULL
    };

  char
    *font_name;

  register const char
    **p;

  XFontStruct
    *font_info;

  font_info=(XFontStruct *) NULL;
  font_name=resource_info->font;
  if (text_font != MagickFalse)
    font_name=resource_info->text_font;
  if ((font_name != (char *) NULL) && (*font_name != '\0'))
    {
      char
        **fontlist;

      register int
        i;

      /*
        Load preferred font specified in the X resource database.
      */
      fontlist=FontToList(font_name);
      if (fontlist != (char **) NULL)
        {
          for (i=0; fontlist[i] != (char *) NULL; i++)
          {
            if (font_info == (XFontStruct *) NULL)
              font_info=XLoadQueryFont(display,fontlist[i]);
            fontlist[i]=DestroyString(fontlist[i]);
          }
          fontlist=(char **) RelinquishMagickMemory(fontlist);
        }
      if (font_info == (XFontStruct *) NULL)
        ThrowXWindowException(XServerError,"UnableToLoadFont",font_name);
    }
  /*
    Load fonts from list of fonts until one is found.
  */
  p=Fonts;
  if (text_font != MagickFalse)
    p=TextFonts;
  if (XDisplayHeight(display,XDefaultScreen(display)) >= 748)
    p++;
  while (*p != (char *) NULL)
  {
    if (font_info != (XFontStruct *) NULL)
      break;
    font_info=XLoadQueryFont(display,(char *) *p);
    p++;
  }
  return(font_info);
}


MagickPrivate Window XWindowByID(Display *display,const Window root_window,
  const size_t id)
{
  RectangleInfo
    rectangle_info;

  register int
    i;

  Status
    status;

  unsigned int
    number_children;

  Window
    child,
    *children,
    window;

  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(display != (Display *) NULL);
  assert(root_window != (Window) NULL);
  if (id == 0)
    return(XSelectWindow(display,&rectangle_info));
  if (root_window == id)
    return(root_window);
  status=XQueryTree(display,root_window,&child,&child,&children,
    &number_children);
  if (status == False)
    return((Window) NULL);
  window=(Window) NULL;
  for (i=0; i < (int) number_children; i++)
  {
    /*
      Search each child and their children.
    */
    window=XWindowByID(display,children[i],id);
    if (window != (Window) NULL)
      break;
  }
  if (children != (Window *) NULL)
    (void) XFree((void *) children);
  return(window);
}


MagickPrivate void XQueryPosition(Display *display,const Window window,int *x,
  int *y)
{
  int
    x_root,
    y_root;

  unsigned int
    mask;

  Window
    root_window;

  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(display != (Display *) NULL);
  assert(window != (Window) NULL);
  assert(x != (int *) NULL);
  assert(y != (int *) NULL);
  (void) XQueryPointer(display,window,&root_window,&root_window,&x_root,&y_root,
    x,y,&mask);
}


MagickPrivate MagickBooleanType XRenderImage(Image *image,
  const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics,
  ExceptionInfo *exception)
{
  const char
    *client_name;

  DrawInfo
    cache_info;

  Display
    *display;

  ImageInfo
    *image_info;

  MagickBooleanType
    status;

  size_t
    height,
    width;

  XAnnotateInfo
    annotate_info;

  XFontStruct
    *font_info;

  XPixelInfo
    pixel;

  XResourceInfo
    resource_info;

  XrmDatabase
    resource_database;

  XStandardColormap
    *map_info;

  XVisualInfo
    *visual_info;

  /*
    Open X server connection.
  */
  display=XOpenDisplay(draw_info->server_name);
  if (display == (Display *) NULL)
    {
      ThrowXWindowException(XServerError,"UnableToOpenXServer",
        draw_info->server_name);
      return(MagickFalse);
    }
  /*
    Get user defaults from X resource database.
  */
  (void) XSetErrorHandler(XError);
  image_info=AcquireImageInfo();
  client_name=GetClientName();
  resource_database=XGetResourceDatabase(display,client_name);
  XGetResourceInfo(image_info,resource_database,client_name,&resource_info);
  resource_info.close_server=MagickFalse;
  resource_info.colormap=PrivateColormap;
  resource_info.font=AcquireString(draw_info->font);
  resource_info.background_color=AcquireString("#ffffffffffff");
  resource_info.foreground_color=AcquireString("#000000000000");
  map_info=XAllocStandardColormap();
  visual_info=(XVisualInfo *) NULL;
  font_info=(XFontStruct *) NULL;
  pixel.pixels=(unsigned long *) NULL;
  if (map_info == (XStandardColormap *) NULL)
    {
      ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
      return(MagickFalse);
    }
  /*
    Initialize visual info.
  */
  visual_info=XBestVisualInfo(display,map_info,&resource_info);
  if (visual_info == (XVisualInfo *) NULL)
    {
      XFreeResources(display,visual_info,map_info,&pixel,font_info,
        &resource_info,(XWindowInfo *) NULL);
      ThrowXWindowException(XServerError,"UnableToGetVisual",image->filename);
      return(MagickFalse);
    }
  map_info->colormap=(Colormap) NULL;
  /*
    Initialize Standard Colormap info.
  */
  XGetMapInfo(visual_info,XDefaultColormap(display,visual_info->screen),
    map_info);
  XGetPixelInfo(display,visual_info,map_info,&resource_info,(Image *) NULL,
    &pixel);
  pixel.annotate_context=XDefaultGC(display,visual_info->screen);
  /*
    Initialize font info.
  */
  font_info=XBestFont(display,&resource_info,MagickFalse);
  if (font_info == (XFontStruct *) NULL)
    {
      XFreeResources(display,visual_info,map_info,&pixel,font_info,
        &resource_info,(XWindowInfo *) NULL);
      ThrowXWindowException(XServerError,"UnableToLoadFont",draw_info->font);
      return(MagickFalse);
    }
  cache_info=(*draw_info);
  /*
    Initialize annotate info.
  */
  XGetAnnotateInfo(&annotate_info);
  annotate_info.stencil=ForegroundStencil;
  if (cache_info.font != draw_info->font)
    {
      /*
        Type name has changed.
      */
      (void) XFreeFont(display,font_info);
      (void) CloneString(&resource_info.font,draw_info->font);
      font_info=XBestFont(display,&resource_info,MagickFalse);
      if (font_info == (XFontStruct *) NULL)
        {
          ThrowXWindowException(XServerError,"UnableToLoadFont",
            draw_info->font);
          return(MagickFalse);
        }
    }
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
      "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
      draw_info->font : "none",draw_info->pointsize);
  cache_info=(*draw_info);
  annotate_info.font_info=font_info;
  annotate_info.text=(char *) draw_info->text;
  annotate_info.width=(unsigned int) XTextWidth(font_info,draw_info->text,(int)
    strlen(draw_info->text));
  annotate_info.height=(unsigned int) font_info->ascent+font_info->descent;
  metrics->pixels_per_em.x=(double) font_info->max_bounds.width;
  metrics->pixels_per_em.y=(double) font_info->ascent+font_info->descent;
  metrics->ascent=(double) font_info->ascent+4;
  metrics->descent=(double) (-font_info->descent);
  metrics->width=annotate_info.width/ExpandAffine(&draw_info->affine);
  metrics->height=(double) font_info->ascent+font_info->descent;
  metrics->max_advance=(double) font_info->max_bounds.width;
  metrics->bounds.x1=0.0;
  metrics->bounds.y1=metrics->descent;
  metrics->bounds.x2=metrics->ascent+metrics->descent;
  metrics->bounds.y2=metrics->ascent+metrics->descent;
  metrics->underline_position=(-2.0);
  metrics->underline_thickness=1.0;
  if (draw_info->render == MagickFalse)
    return(MagickTrue);
  if (draw_info->fill.alpha == TransparentAlpha)
    return(MagickTrue);
  /*
    Render fill color.
  */
  width=annotate_info.width;
  height=annotate_info.height;
  if ((fabs(draw_info->affine.rx) >= MagickEpsilon) ||
      (fabs(draw_info->affine.ry) >= MagickEpsilon))
    {
      if ((fabs(draw_info->affine.sx-draw_info->affine.sy) < MagickEpsilon) &&
          (fabs(draw_info->affine.rx+draw_info->affine.ry) < MagickEpsilon))
        annotate_info.degrees=(double) (180.0/MagickPI)*
          atan2(draw_info->affine.rx,draw_info->affine.sx);
    }
  (void) FormatLocaleString(annotate_info.geometry,MagickPathExtent,
    "%.20gx%.20g%+.20g%+.20g",(double) width,(double) height,
    ceil(offset->x-0.5),ceil(offset->y-metrics->ascent-metrics->descent+
    draw_info->interline_spacing-0.5));
  pixel.pen_color.red=ScaleQuantumToShort(
    ClampToQuantum(draw_info->fill.red));
  pixel.pen_color.green=ScaleQuantumToShort(
    ClampToQuantum(draw_info->fill.green));
  pixel.pen_color.blue=ScaleQuantumToShort(
    ClampToQuantum(draw_info->fill.blue));
  status=XAnnotateImage(display,&pixel,&annotate_info,image,exception);
  if (status == 0)
    {
      ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
      return(MagickFalse);
    }
  return(MagickTrue);
}


static void XMakeImageLSBFirst(const XResourceInfo *resource_info,
  const XWindowInfo *window,Image *image,XImage *ximage,XImage *matte_image,
  ExceptionInfo *exception)
{
  CacheView
    *canvas_view;

  Image
    *canvas;

  int
    y;

  register const Quantum
    *p;

  register int
    x;

  register unsigned char
    *q;

  unsigned char
    bit,
    byte;

  unsigned int
    scanline_pad;

  unsigned long
    pixel,
    *pixels;

  XStandardColormap
    *map_info;

  assert(resource_info != (XResourceInfo *) NULL);
  assert(window != (XWindowInfo *) NULL);
  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  canvas=image;
  if ((window->immutable == MagickFalse) &&
      (image->storage_class == DirectClass) && (image->alpha_trait != UndefinedPixelTrait))
    {
      char
        size[MagickPathExtent];

      Image
        *pattern;

      ImageInfo
        *image_info;

      image_info=AcquireImageInfo();
      (void) CopyMagickString(image_info->filename,
        resource_info->image_info->texture != (char *) NULL ?
        resource_info->image_info->texture : "pattern:checkerboard",
        MagickPathExtent);
      (void) FormatLocaleString(size,MagickPathExtent,"%.20gx%.20g",(double)
        image->columns,(double) image->rows);
      image_info->size=ConstantString(size);
      pattern=ReadImage(image_info,exception);
      image_info=DestroyImageInfo(image_info);
      if (pattern != (Image *) NULL)
        {
          canvas=CloneImage(image,0,0,MagickTrue,exception);
          if (canvas != (Image *) NULL)
            (void) CompositeImage(canvas,pattern,DstOverCompositeOp,MagickTrue,
              0,0,exception);
          pattern=DestroyImage(pattern);
        }
    }
  scanline_pad=(unsigned int) (ximage->bytes_per_line-((ximage->width*
    ximage->bits_per_pixel) >> 3));
  map_info=window->map_info;
  pixels=window->pixel_info->pixels;
  q=(unsigned char *) ximage->data;
  x=0;
  canvas_view=AcquireVirtualCacheView(canvas,exception);
  if (ximage->format == XYBitmap)
    {
      register unsigned short
        polarity;

      unsigned char
        background,
        foreground;

      /*
        Convert canvas to big-endian bitmap.
      */
      background=(unsigned char)
        (XPixelIntensity(&window->pixel_info->foreground_color) <
         XPixelIntensity(&window->pixel_info->background_color) ? 0x80 : 0x00);
      foreground=(unsigned char)
        (XPixelIntensity(&window->pixel_info->background_color) <
         XPixelIntensity(&window->pixel_info->foreground_color) ? 0x80 : 0x00);
      polarity=(unsigned short) ((GetPixelInfoIntensity(image,
        &canvas->colormap[0])) < (QuantumRange/2.0) ? 1 : 0);
      if (canvas->colors == 2)
        polarity=GetPixelInfoIntensity(image,&canvas->colormap[0]) <
          GetPixelInfoIntensity(image,&canvas->colormap[1]);
      for (y=0; y < (int) canvas->rows; y++)
      {
        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
          exception);
        if (p == (const Quantum *) NULL)
          break;
        bit=0;
        byte=0;
        for (x=0; x < (int) canvas->columns; x++)
        {
          byte>>=1;
          if (GetPixelIndex(canvas,p) == (Quantum) polarity)
            byte|=foreground;
          else
            byte|=background;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          p+=GetPixelChannels(canvas);
        }
        if (bit != 0)
          *q=byte >> (8-bit);
        q+=scanline_pad;
      }
    }
  else
    if (window->pixel_info->colors != 0)
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to 2 bit color-mapped X canvas.
          */
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            nibble=0;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)] & 0x0f;
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) (pixel << 6);
                  q++;
                  nibble=0;
                  break;
                }
              }
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to 4 bit color-mapped X canvas.
          */
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            nibble=0;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)] & 0xf;
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  q++;
                  nibble=0;
                  break;
                }
              }
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to 8 bit color-mapped X canvas.
          */
          if (resource_info->color_recovery &&
              resource_info->quantize_info->dither_method != NoDitherMethod)
            {
              XDitherImage(canvas,ximage,exception);
              break;
            }
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)];
              *q++=(unsigned char) pixel;
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        default:
        {
          register int
            k;

          register unsigned int
            bytes_per_pixel;

          /*
            Convert to multi-byte color-mapped X canvas.
          */
          bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)];
              for (k=0; k < (int) bytes_per_pixel; k++)
              {
                *q++=(unsigned char) (pixel & 0xff);
                pixel>>=8;
              }
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
      }
    else
      switch (ximage->bits_per_pixel)
      {
        case 2:
        {
          register unsigned int
            nibble;

          /*
            Convert to contiguous 2 bit continuous-tone X canvas.
          */
          for (y=0; y < (int) canvas->rows; y++)
          {
            nibble=0;
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=XGammaPixel(canvas,map_info,p);
              pixel&=0xf;
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 2);
                  nibble++;
                  break;
                }
                case 2:
                {
                  *q|=(unsigned char) (pixel << 4);
                  nibble++;
                  break;
                }
                case 3:
                {
                  *q|=(unsigned char) (pixel << 6);
                  q++;
                  nibble=0;
                  break;
                }
              }
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        case 4:
        {
          register unsigned int
            nibble;

          /*
            Convert to contiguous 4 bit continuous-tone X canvas.
          */
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            nibble=0;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=XGammaPixel(canvas,map_info,p);
              pixel&=0xf;
              switch (nibble)
              {
                case 0:
                {
                  *q=(unsigned char) pixel;
                  nibble++;
                  break;
                }
                case 1:
                {
                  *q|=(unsigned char) (pixel << 4);
                  q++;
                  nibble=0;
                  break;
                }
              }
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        case 6:
        case 8:
        {
          /*
            Convert to contiguous 8 bit continuous-tone X canvas.
          */
          if (resource_info->color_recovery &&
              resource_info->quantize_info->dither_method != NoDitherMethod)
            {
              XDitherImage(canvas,ximage,exception);
              break;
            }
          for (y=0; y < (int) canvas->rows; y++)
          {
            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
              canvas->columns,1,exception);
            if (p == (const Quantum *) NULL)
              break;
            for (x=0; x < (int) canvas->columns; x++)
            {
              pixel=XGammaPixel(canvas,map_info,p);
              *q++=(unsigned char) pixel;
              p+=GetPixelChannels(canvas);
            }
            q+=scanline_pad;
          }
          break;
        }
        default:
        {
          if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
              (map_info->green_max == 255) && (map_info->blue_max == 255) &&
              (map_info->red_mult == 65536L) && (map_info->green_mult == 256) &&
              (map_info->blue_mult == 1))
            {
              /*
                Convert to 32 bit continuous-tone X canvas.
              */
              for (y=0; y < (int) canvas->rows; y++)
              {
                p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
                  canvas->columns,1,exception);
                if (p == (const Quantum *) NULL)
                  break;
                if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
                    (blue_gamma != 1.0))
                  {
                    /*
                      Gamma correct canvas.
                    */
                    for (x=(int) canvas->columns-1; x >= 0; x--)
                    {
                      *q++=ScaleQuantumToChar(XBlueGamma(
                        GetPixelBlue(canvas,p)));
                      *q++=ScaleQuantumToChar(XGreenGamma(
                        GetPixelGreen(canvas,p)));
                      *q++=ScaleQuantumToChar(XRedGamma(
                        GetPixelRed(canvas,p)));
                      *q++=0;
                      p+=GetPixelChannels(canvas);
                    }
                    continue;
                  }
                for (x=(int) canvas->columns-1; x >= 0; x--)
                {
                  *q++=ScaleQuantumToChar((Quantum) GetPixelBlue(canvas,p));
                  *q++=ScaleQuantumToChar((Quantum) GetPixelGreen(canvas,p));
                  *q++=ScaleQuantumToChar((Quantum) GetPixelRed(canvas,p));
                  *q++=0;
                  p+=GetPixelChannels(canvas);
                }
              }
            }
          else
            if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
                (map_info->green_max == 255) && (map_info->blue_max == 255) &&
                (map_info->red_mult == 1) && (map_info->green_mult == 256) &&
                (map_info->blue_mult == 65536L))
              {
                /*
                  Convert to 32 bit continuous-tone X canvas.
                */
                for (y=0; y < (int) canvas->rows; y++)
                {
                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
                    canvas->columns,1,exception);
                  if (p == (const Quantum *) NULL)
                    break;
                  if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
                      (blue_gamma != 1.0))
                    {
                      /*
                        Gamma correct canvas.
                      */
                      for (x=(int) canvas->columns-1; x >= 0; x--)
                      {
                        *q++=ScaleQuantumToChar(XRedGamma(
                          GetPixelRed(canvas,p)));
                        *q++=ScaleQuantumToChar(XGreenGamma(
                          GetPixelGreen(canvas,p)));
                        *q++=ScaleQuantumToChar(XBlueGamma(
                          GetPixelBlue(canvas,p)));
                        *q++=0;
                        p+=GetPixelChannels(canvas);
                      }
                      continue;
                    }
                  for (x=(int) canvas->columns-1; x >= 0; x--)
                  {
                    *q++=ScaleQuantumToChar((Quantum) GetPixelRed(canvas,p));
                    *q++=ScaleQuantumToChar((Quantum) GetPixelGreen(canvas,p));
                    *q++=ScaleQuantumToChar((Quantum) GetPixelBlue(canvas,p));
                    *q++=0;
                    p+=GetPixelChannels(canvas);
                  }
                }
              }
            else
              {
                register int
                  k;

                register unsigned int
                  bytes_per_pixel;

                /*
                  Convert to multi-byte continuous-tone X canvas.
                */
                bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
                for (y=0; y < (int) canvas->rows; y++)
                {
                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
                    canvas->columns,1,exception);
                  if (p == (const Quantum *) NULL)
                    break;
                  for (x=0; x < (int) canvas->columns; x++)
                  {
                    pixel=XGammaPixel(canvas,map_info,p);
                    for (k=0; k < (int) bytes_per_pixel; k++)
                    {
                      *q++=(unsigned char) (pixel & 0xff);
                      pixel>>=8;
                    }
                    p+=GetPixelChannels(canvas);
                  }
                  q+=scanline_pad;
                }
              }
          break;
        }
      }
  if (matte_image != (XImage *) NULL)
    {
      /*
        Initialize matte canvas.
      */
      scanline_pad=(unsigned int) (matte_image->bytes_per_line-
        ((matte_image->width*matte_image->bits_per_pixel) >> 3));
      q=(unsigned char *) matte_image->data;
      for (y=0; y < (int) canvas->rows; y++)
      {
        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
          exception);
        if (p == (const Quantum *) NULL)
          break;
        bit=0;
        byte=0;
        for (x=(int) canvas->columns-1; x >= 0; x--)
        {
          byte>>=1;
          if (GetPixelAlpha(canvas,p) > (QuantumRange/2))
            byte|=0x80;
          bit++;
          if (bit == 8)
            {
              *q++=byte;
              bit=0;
              byte=0;
            }
          p+=GetPixelChannels(canvas);
        }
        if (bit != 0)
          *q=byte >> (8-bit);
        q+=scanline_pad;
      }
    }
  canvas_view=DestroyCacheView(canvas_view);
  if (canvas != image)
    canvas=DestroyImage(canvas);
}


MagickPrivate void XGetWindowInfo(Display *display,XVisualInfo *visual_info,
  XStandardColormap *map_info,XPixelInfo *pixel,XFontStruct *font_info,
  XResourceInfo *resource_info,XWindowInfo *window)
{
  /*
    Initialize window info.
  */
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(display != (Display *) NULL);
  assert(visual_info != (XVisualInfo *) NULL);
  assert(map_info != (XStandardColormap *) NULL);
  assert(pixel != (XPixelInfo *) NULL);
  assert(resource_info != (XResourceInfo *) NULL);
  assert(window != (XWindowInfo *) NULL);
  if (window->id != (Window) NULL)
    {
      if (window->cursor != (Cursor) NULL)
        (void) XFreeCursor(display,window->cursor);
      if (window->busy_cursor != (Cursor) NULL)
        (void) XFreeCursor(display,window->busy_cursor);
      if (window->highlight_stipple != (Pixmap) NULL)
        (void) XFreePixmap(display,window->highlight_stipple);
      if (window->shadow_stipple != (Pixmap) NULL)
        (void) XFreePixmap(display,window->shadow_stipple);
      if (window->name == (char *) NULL)
        window->name=AcquireString("");
      if (window->icon_name == (char *) NULL)
        window->icon_name=AcquireString("");
    }
  else
    {
      /*
        Initialize these attributes just once.
      */
      window->id=(Window) NULL;
      if (window->name == (char *) NULL)
        window->name=AcquireString("");
      if (window->icon_name == (char *) NULL)
        window->icon_name=AcquireString("");
      window->x=XDisplayWidth(display,visual_info->screen) >> 1;
      window->y=XDisplayWidth(display,visual_info->screen) >> 1;
      window->ximage=(XImage *) NULL;
      window->matte_image=(XImage *) NULL;
      window->pixmap=(Pixmap) NULL;
      window->matte_pixmap=(Pixmap) NULL;
      window->mapped=MagickFalse;
      window->stasis=MagickFalse;
      window->shared_memory=MagickTrue;
      window->segment_info=(void *) NULL;
#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
      {
        XShmSegmentInfo
          *segment_info;

        if (window->segment_info == (void *) NULL)
          window->segment_info=AcquireCriticalMemory(2*sizeof(*segment_info));
        segment_info=(XShmSegmentInfo *) window->segment_info;
        segment_info[0].shmid=(-1);
        segment_info[0].shmaddr=(char *) NULL;
        segment_info[1].shmid=(-1);
        segment_info[1].shmaddr=(char *) NULL;
      }
#endif
    }
  /*
    Initialize these attributes every time function is called.
  */
  window->screen=visual_info->screen;
  window->root=XRootWindow(display,visual_info->screen);
  window->visual=visual_info->visual;
  window->storage_class=(unsigned int) visual_info->klass;
  window->depth=(unsigned int) visual_info->depth;
  window->visual_info=visual_info;
  window->map_info=map_info;
  window->pixel_info=pixel;
  window->font_info=font_info;
  window->cursor=XCreateFontCursor(display,XC_left_ptr);
  window->busy_cursor=XCreateFontCursor(display,XC_watch);
  window->geometry=(char *) NULL;
  window->icon_geometry=(char *) NULL;
  if (resource_info->icon_geometry != (char *) NULL)
    (void) CloneString(&window->icon_geometry,resource_info->icon_geometry);
  window->crop_geometry=(char *) NULL;
  window->flags=(size_t) PSize;
  window->width=1;
  window->height=1;
  window->min_width=1;
  window->min_height=1;
  window->width_inc=1;
  window->height_inc=1;
  window->border_width=resource_info->border_width;
  window->annotate_context=pixel->annotate_context;
  window->highlight_context=pixel->highlight_context;
  window->widget_context=pixel->widget_context;
  window->shadow_stipple=(Pixmap) NULL;
  window->highlight_stipple=(Pixmap) NULL;
  window->use_pixmap=MagickTrue;
  window->immutable=MagickFalse;
  window->shape=MagickFalse;
  window->data=0;
  window->mask=(int) (CWBackingStore | CWBackPixel | CWBackPixmap |
    CWBitGravity | CWBorderPixel | CWColormap | CWCursor | CWDontPropagate |
    CWEventMask | CWOverrideRedirect | CWSaveUnder | CWWinGravity);
  window->attributes.background_pixel=pixel->background_color.pixel;
  window->attributes.background_pixmap=(Pixmap) NULL;
  window->attributes.bit_gravity=ForgetGravity;
  window->attributes.backing_store=WhenMapped;
  window->attributes.save_under=MagickTrue;
  window->attributes.border_pixel=pixel->border_color.pixel;
  window->attributes.colormap=map_info->colormap;
  window->attributes.cursor=window->cursor;
  window->attributes.do_not_propagate_mask=NoEventMask;
  window->attributes.event_mask=NoEventMask;
  window->attributes.override_redirect=MagickFalse;
  window->attributes.win_gravity=NorthWestGravity;
  window->orphan=MagickFalse;
}


MagickExport int XError(Display *display,XErrorEvent *error)
{
  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(display != (Display *) NULL);
  assert(error != (XErrorEvent *) NULL);
  xerror_alert=MagickTrue;
  switch (error->request_code)
  {
    case X_GetGeometry:
    {
      if ((int) error->error_code == BadDrawable)
        return(MagickFalse);
      break;
    }
    case X_GetWindowAttributes:
    case X_QueryTree:
    {
      if ((int) error->error_code == BadWindow)
        return(MagickFalse);
      break;
    }
    case X_QueryColors:
    {
      if ((int) error->error_code == BadValue)
        return(MagickFalse);
      break;
    }
  }
  return(MagickTrue);
}


do_pause ()
{
  int i;
  struct sigaction act;
  int const sig[] =
    {
     SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGPOLL,
     SIGPROF, SIGVTALRM, SIGXCPU, SIGXFSZ, 0
    };

  act.sa_handler = SIG_IGN;

  for (i = 0; sig[i]; i++)
    sigaction (sig[i], &act, NULL);

  prctl (PR_SET_NAME, "podman pause", NULL, NULL, NULL);
  while (1)
    pause ();
}


get_cmd_line_args (pid_t pid)
{
  int fd;
  char path[PATH_MAX];
  char *buffer;
  size_t allocated;
  size_t used = 0;
  int ret;
  int i, argc = 0;
  char **argv;

  if (pid)
    sprintf (path, "/proc/%d/cmdline", pid);
  else
    strcpy (path, "/proc/self/cmdline");
  fd = open (path, O_RDONLY);
  if (fd < 0)
    return NULL;

  allocated = 512;
  buffer = malloc (allocated);
  if (buffer == NULL)
    return NULL;
  for (;;)
    {
      ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used));
      if (ret < 0)
        {
          free (buffer);
          return NULL;
        }

      if (ret == 0)
        break;

      used += ret;
      if (allocated == used)
        {
          allocated += 512;
          char *tmp = realloc (buffer, allocated);
          if (tmp == NULL)
            {
              free (buffer);
              return NULL;
            }
	  buffer = tmp;
        }
    }
  close (fd);

  for (i = 0; i < used; i++)
    if (buffer[i] == '\0')
      argc++;
  if (argc == 0)
    {
      free (buffer);
      return NULL;
    }

  argv = malloc (sizeof (char *) * (argc + 1));
  if (argv == NULL)
    {
      free (buffer);
      return NULL;
    }
  argc = 0;

  argv[argc++] = buffer;
  for (i = 0; i < used - 1; i++)
    if (buffer[i] == '\0')
      argv[argc++] = buffer + i + 1;

  argv[argc] = NULL;

  return argv;
}


int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
{
    sig_cb_st sig;
    sig.sigalgcnt = 0;
    if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
        return 0;
    if (c == NULL)
        return 1;
    return tls1_set_raw_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
}


int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey)
{
    size_t idx;
    const SIGALG_LOOKUP *lu;

    if (ssl_cert_lookup_by_pkey(pkey, &idx) == NULL)
        return 0;
    lu = tls1_get_legacy_sigalg(s, idx);
    if (lu == NULL)
        return 0;
    s->s3.tmp.peer_sigalg = lu;
    return 1;
}


void tls1_free(SSL *s)
{
    OPENSSL_free(s->ext.session_ticket);
    ssl3_free(s);
}


static int tls1_in_list(uint16_t id, const uint16_t *list, size_t listlen)
{
    size_t i;
    for (i = 0; i < listlen; i++)
        if (list[i] == id)
            return 1;
    return 0;
}


int SSL_get_sigalgs(SSL *s, int idx,
                    int *psign, int *phash, int *psignhash,
                    unsigned char *rsig, unsigned char *rhash)
{
    uint16_t *psig = s->s3.tmp.peer_sigalgs;
    size_t numsigalgs = s->s3.tmp.peer_sigalgslen;
    if (psig == NULL || numsigalgs > INT_MAX)
        return 0;
    if (idx >= 0) {
        const SIGALG_LOOKUP *lu;

        if (idx >= (int)numsigalgs)
            return 0;
        psig += idx;
        if (rhash != NULL)
            *rhash = (unsigned char)((*psig >> 8) & 0xff);
        if (rsig != NULL)
            *rsig = (unsigned char)(*psig & 0xff);
        lu = tls1_lookup_sigalg(*psig);
        if (psign != NULL)
            *psign = lu != NULL ? lu->sig : NID_undef;
        if (phash != NULL)
            *phash = lu != NULL ? lu->hash : NID_undef;
        if (psignhash != NULL)
            *psignhash = lu != NULL ? lu->sigandhash : NID_undef;
    }
    return (int)numsigalgs;
}


int tls_valid_group(SSL *s, uint16_t group_id, int version)
{
    const TLS_GROUP_INFO *ginfo = tls1_group_id_lookup(group_id);

    if (version < TLS1_3_VERSION) {
        if ((ginfo->flags & TLS_GROUP_ONLY_FOR_TLS1_3) != 0)
            return 0;
    }
    return 1;
}


int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op, int ecdhe)
{
    if (c->algorithm_mkey & s->s3.tmp.mask_k
        || c->algorithm_auth & s->s3.tmp.mask_a)
        return 1;
    if (s->s3.tmp.max_ver == 0)
        return 1;
    if (!SSL_IS_DTLS(s)) {
        int min_tls = c->min_tls;

        /*
         * For historical reasons we will allow ECHDE to be selected by a server
         * in SSLv3 if we are a client
         */
        if (min_tls == TLS1_VERSION && ecdhe
                && (c->algorithm_mkey & (SSL_kECDHE | SSL_kECDHEPSK)) != 0)
            min_tls = SSL3_VERSION;

        if ((min_tls > s->s3.tmp.max_ver) || (c->max_tls < s->s3.tmp.min_ver))
            return 1;
    }
    if (SSL_IS_DTLS(s) && (DTLS_VERSION_GT(c->min_dtls, s->s3.tmp.max_ver)
                           || DTLS_VERSION_LT(c->max_dtls, s->s3.tmp.min_ver)))
        return 1;

    return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
}


int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd)
{
    const EVP_MD *md;
    if (lu == NULL)
        return 0;
    /* lu->hash == NID_undef means no associated digest */
    if (lu->hash == NID_undef) {
        md = NULL;
    } else {
        md = ssl_md(lu->hash_idx);
        if (md == NULL)
            return 0;
    }
    if (pmd)
        *pmd = md;
    return 1;
}


int tls_choose_sigalg(SSL *s, int fatalerrs)
{
    const SIGALG_LOOKUP *lu = NULL;
    int sig_idx = -1;

    s->s3.tmp.cert = NULL;
    s->s3.tmp.sigalg = NULL;

    if (SSL_IS_TLS13(s)) {
        lu = find_sig_alg(s, NULL, NULL);
        if (lu == NULL) {
            if (!fatalerrs)
                return 1;
            SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_CHOOSE_SIGALG,
                     SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
            return 0;
        }
    } else {
        /* If ciphersuite doesn't require a cert nothing to do */
        if (!(s->s3.tmp.new_cipher->algorithm_auth & SSL_aCERT))
            return 1;
        if (!s->server && !ssl_has_cert(s, s->cert->key - s->cert->pkeys))
                return 1;

        if (SSL_USE_SIGALGS(s)) {
            size_t i;
            if (s->s3.tmp.peer_sigalgs != NULL) {
#ifndef OPENSSL_NO_EC
                int curve = -1;

                /* For Suite B need to match signature algorithm to curve */
                if (tls1_suiteb(s))
                    curve =
                        evp_pkey_get_EC_KEY_curve_nid(s->cert->pkeys[SSL_PKEY_ECC]
                                                      .privatekey);
#endif

                /*
                 * Find highest preference signature algorithm matching
                 * cert type
                 */
                for (i = 0; i < s->shared_sigalgslen; i++) {
                    lu = s->shared_sigalgs[i];

                    if (s->server) {
                        if ((sig_idx = tls12_get_cert_sigalg_idx(s, lu)) == -1)
                            continue;
                    } else {
                        int cc_idx = s->cert->key - s->cert->pkeys;

                        sig_idx = lu->sig_idx;
                        if (cc_idx != sig_idx)
                            continue;
                    }
                    /* Check that we have a cert, and sig_algs_cert */
                    if (!has_usable_cert(s, lu, sig_idx))
                        continue;
                    if (lu->sig == EVP_PKEY_RSA_PSS) {
                        /* validate that key is large enough for the signature algorithm */
                        EVP_PKEY *pkey = s->cert->pkeys[sig_idx].privatekey;

                        if (!rsa_pss_check_min_key_size(s->ctx, pkey, lu))
                            continue;
                    }
#ifndef OPENSSL_NO_EC
                    if (curve == -1 || lu->curve == curve)
#endif
                        break;
                }
#ifndef OPENSSL_NO_GOST
                /*
                 * Some Windows-based implementations do not send GOST algorithms indication
                 * in supported_algorithms extension, so when we have GOST-based ciphersuite,
                 * we have to assume GOST support.
                 */
                if (i == s->shared_sigalgslen && s->s3.tmp.new_cipher->algorithm_auth & (SSL_aGOST01 | SSL_aGOST12)) {
                  if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
                    if (!fatalerrs)
                      return 1;
                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                             SSL_F_TLS_CHOOSE_SIGALG,
                             SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
                    return 0;
                  } else {
                    i = 0;
                    sig_idx = lu->sig_idx;
                  }
                }
#endif
                if (i == s->shared_sigalgslen) {
                    if (!fatalerrs)
                        return 1;
                    SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
                             SSL_F_TLS_CHOOSE_SIGALG,
                             SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
                    return 0;
                }
            } else {
                /*
                 * If we have no sigalg use defaults
                 */
                const uint16_t *sent_sigs;
                size_t sent_sigslen;

                if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
                    if (!fatalerrs)
                        return 1;
                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CHOOSE_SIGALG,
                             SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
                    return 0;
                }

                /* Check signature matches a type we sent */
                sent_sigslen = tls12_get_psigalgs(s, 1, &sent_sigs);
                for (i = 0; i < sent_sigslen; i++, sent_sigs++) {
                    if (lu->sigalg == *sent_sigs
                            && has_usable_cert(s, lu, lu->sig_idx))
                        break;
                }
                if (i == sent_sigslen) {
                    if (!fatalerrs)
                        return 1;
                    SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
                             SSL_F_TLS_CHOOSE_SIGALG,
                             SSL_R_WRONG_SIGNATURE_TYPE);
                    return 0;
                }
            }
        } else {
            if ((lu = tls1_get_legacy_sigalg(s, -1)) == NULL) {
                if (!fatalerrs)
                    return 1;
                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CHOOSE_SIGALG,
                         SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM);
                return 0;
            }
        }
    }
    if (sig_idx == -1)
        sig_idx = lu->sig_idx;
    s->s3.tmp.cert = &s->cert->pkeys[sig_idx];
    s->cert->key = s->s3.tmp.cert;
    s->s3.tmp.sigalg = lu;
    return 1;
}


int ssl_hmac_init(SSL_HMAC *ctx, void *key, size_t len, char *md)
{
    OSSL_PARAM params[3], *p = params;

    if (ctx->ctx != NULL) {
        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, md, 0);
        *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key, len);
        *p = OSSL_PARAM_construct_end();
        if (EVP_MAC_CTX_set_params(ctx->ctx, params) && EVP_MAC_init(ctx->ctx))
            return 1;
    }
#ifndef OPENSSL_NO_DEPRECATED_3_0
    if (ctx->old_ctx != NULL)
        return HMAC_Init_ex(ctx->old_ctx, key, len,
                            EVP_get_digestbyname(md), NULL);
#endif
    return 0;
}


static int totp_sha3(gnutls_session_t session,
		uint64_t t,
		const gnutls_datum_t *secret,
		uint8_t out[TICKET_MASTER_KEY_SIZE])
{
	int retval;
	uint8_t t_be[8];
	digest_hd_st hd;
	/*
	 * We choose SHA3-512 because it outputs 64 bytes,
	 * just the same length as the ticket key.
	 */
	const gnutls_digest_algorithm_t algo = GNUTLS_DIG_SHA3_512;
#if TICKET_MASTER_KEY_SIZE != 64
#error "TICKET_MASTER_KEY_SIZE must be 64 bytes"
#endif

	if (unlikely(secret == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if ((retval = _gnutls_hash_init(&hd, hash_to_entry(algo))) < 0)
		return gnutls_assert_val(retval);

	_gnutls_write_uint64(t, t_be);

	if ((retval = _gnutls_hash(&hd, t_be, sizeof(t_be))) < 0)
		return gnutls_assert_val(retval);
	if ((retval = _gnutls_hash(&hd, secret->data, secret->size)) < 0)
		return gnutls_assert_val(retval);

	_gnutls_hash_deinit(&hd, out);
	return GNUTLS_E_SUCCESS;
}


void doit(void)
{
	int resume[] = { 0, 1, 0 };

	signal(SIGCHLD, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	num_stek_rotations = 0;
	run("tls1.2 resumption", "NORMAL:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0", resume, 3);

	num_stek_rotations = 0;
	run("tls1.3 resumption", "NORMAL:-VERS-ALL:+VERS-TLS1.3", resume, 3);
}


static uint64_t T(gnutls_session_t session, time_t t)
{
	uint64_t numeral = t;
	unsigned int x = session->internals.expire_time * STEK_ROTATION_PERIOD_PRODUCT;

	if (numeral <= 0)
		return 0;

	return (numeral / x);
}


static bool _gnutls_has_cert_credentials(gnutls_session_t session,
						gnutls_certificate_type_t cert_type)
{
	unsigned i;
	unsigned cert_found = 0;
	gnutls_certificate_credentials_t cred;

	/* First, check for certificate credentials. If we have no certificate
	 * credentials set then we don't support certificates at all.
	 */
	cred = (gnutls_certificate_credentials_t)
			_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);

	if (cred == NULL)
		return false;

	/* There are credentials initialized. Now check whether we can find
	 * pre-set certificates of the required type, but only if we don't
	 * use the callback functions.
	 */
	if (cred->get_cert_callback3 == NULL) {
		for (i = 0; i < cred->ncerts; i++) {
			if (cred->certs[i].cert_list[0].type == cert_type) {
				cert_found = 1;
				break;
			}
		}

		if (cert_found == 0) {
			/* No matching certificate found. */
			return false;
		}
	}

	return true; // OK
}


void _gnutls_session_server_cert_type_set(gnutls_session_t session,
			      gnutls_certificate_type_t ct)
{
	_gnutls_handshake_log
	    ("HSK[%p]: Selected server certificate type %s (%d)\n", session,
	     gnutls_certificate_type_get_name(ct), ct);
	session->security_parameters.server_ctype = ct;
}


_gnutls_session_cert_type_supported(gnutls_session_t session,
				    gnutls_certificate_type_t cert_type,
				    bool check_credentials,
				    gnutls_ctype_target_t target)
{
	unsigned i;
	priority_st* ctype_priorities;

	// Check whether this cert type is enabled by the application
	if (!is_cert_type_enabled(session, cert_type))
		return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);

	// Perform a credentials check if requested
	if (check_credentials)	{
		if (!_gnutls_has_cert_credentials(session, cert_type))
			return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
	}

	/* So far so good. We have the required credentials (if needed).
	 * Now check whether we are allowed to use them according to our
	 * priorities.
	 */
	// Which certificate type should we query?
	switch (target) {
		case GNUTLS_CTYPE_CLIENT:
			ctype_priorities =
					&(session->internals.priorities->client_ctype);
			break;
		case GNUTLS_CTYPE_SERVER:
			ctype_priorities =
					&(session->internals.priorities->server_ctype);
			break;
		default:
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
	}

	// No explicit priorities set, and default ctype is asked
	if (ctype_priorities->num_priorities == 0
	    && cert_type == DEFAULT_CERT_TYPE)
		return 0;

	/* Now lets find out whether our cert type is in our priority
	 * list, i.e. set of allowed cert types.
	 */
	for (i = 0; i < ctype_priorities->num_priorities; i++) {
		if (ctype_priorities->priorities[i] == cert_type)
			return 0;
	}

	return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
}


void _gnutls_session_client_cert_type_set(gnutls_session_t session,
			      gnutls_certificate_type_t ct)
{
	_gnutls_handshake_log
	    ("HSK[%p]: Selected client certificate type %s (%d)\n", session,
	     gnutls_certificate_type_get_name(ct), ct);
	session->security_parameters.client_ctype = ct;
}


napi_status napi_create_type_error(napi_env env,
                                   napi_value code,
                                   napi_value msg,
                                   napi_value* result) {
  CHECK_ENV(env);
  CHECK_ARG(env, msg);
  CHECK_ARG(env, result);

  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);

  v8::Local<v8::Value> error_obj =
      v8::Exception::TypeError(message_value.As<v8::String>());
  napi_status status = set_error_code(env, error_obj, code, nullptr);
  if (status != napi_ok) return status;

  *result = v8impl::JsValueFromV8LocalValue(error_obj);

  return napi_clear_last_error(env);
}


napi_status napi_get_typedarray_info(napi_env env,
                                     napi_value typedarray,
                                     napi_typedarray_type* type,
                                     size_t* length,
                                     void** data,
                                     napi_value* arraybuffer,
                                     size_t* byte_offset) {
  CHECK_ENV(env);
  CHECK_ARG(env, typedarray);

  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);

  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();

  if (type != nullptr) {
    if (value->IsInt8Array()) {
      *type = napi_int8_array;
    } else if (value->IsUint8Array()) {
      *type = napi_uint8_array;
    } else if (value->IsUint8ClampedArray()) {
      *type = napi_uint8_clamped_array;
    } else if (value->IsInt16Array()) {
      *type = napi_int16_array;
    } else if (value->IsUint16Array()) {
      *type = napi_uint16_array;
    } else if (value->IsInt32Array()) {
      *type = napi_int32_array;
    } else if (value->IsUint32Array()) {
      *type = napi_uint32_array;
    } else if (value->IsFloat32Array()) {
      *type = napi_float32_array;
    } else if (value->IsFloat64Array()) {
      *type = napi_float64_array;
    } else if (value->IsBigInt64Array()) {
      *type = napi_bigint64_array;
    } else if (value->IsBigUint64Array()) {
      *type = napi_biguint64_array;
    }
  }

  if (length != nullptr) {
    *length = array->Length();
  }

  v8::Local<v8::ArrayBuffer> buffer;
  if (data != nullptr || arraybuffer != nullptr) {
    // Calling Buffer() may have the side effect of allocating the buffer,
    // so only do this when it’s needed.
    buffer = array->Buffer();
  }

  if (data != nullptr) {
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
            array->ByteOffset();
  }

  if (arraybuffer != nullptr) {
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
  }

  if (byte_offset != nullptr) {
    *byte_offset = array->ByteOffset();
  }

  return napi_clear_last_error(env);
}


static napi_value Utf16Length(napi_env env, napi_callback_info info) {
  size_t argc = 1;
  napi_value args[1];
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

  NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");

  napi_valuetype valuetype;
  NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));

  NAPI_ASSERT(env, valuetype == napi_string,
      "Wrong type of argment. Expects a string.");

  size_t length;
  NAPI_CALL(env, napi_get_value_string_utf16(env, args[0], NULL, 0, &length));

  napi_value output;
  NAPI_CALL(env, napi_create_uint32(env, (uint32_t)length, &output));

  return output;
}


  explicit GetterCallbackWrapper(
      const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
      : CallbackWrapperBase(cbinfo, 0) {}


napi_status napi_is_exception_pending(napi_env env, bool* result) {
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
  // pending exception.
  CHECK_ENV(env);
  CHECK_ARG(env, result);

  *result = !env->last_exception.IsEmpty();
  return napi_clear_last_error(env);
}


static void DeleteCallbackBundle(napi_env env, void* data, void* hint) {
  CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
  delete bundle;
}


napi_status napi_get_cb_info(
    napi_env env,               // [in] NAPI environment handle
    napi_callback_info cbinfo,  // [in] Opaque callback-info handle
    size_t* argc,      // [in-out] Specifies the size of the provided argv array
                       // and receives the actual count of args.
    napi_value* argv,  // [out] Array of values
    napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
    void** data) {         // [out] Receives the data pointer for the callback.
  CHECK_ENV(env);
  CHECK_ARG(env, cbinfo);

  v8impl::CallbackWrapper* info =
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);

  if (argv != nullptr) {
    CHECK_ARG(env, argc);
    info->Args(argv, *argc);
  }
  if (argc != nullptr) {
    *argc = info->ArgsLength();
  }
  if (this_arg != nullptr) {
    *this_arg = info->This();
  }
  if (data != nullptr) {
    *data = info->Data();
  }

  return napi_clear_last_error(env);
}


  inline uint32_t Unref() {
    if (_refcount == 0) {
        return 0;
    }
    return --_refcount;
  }


  napi_value GetNewTarget() override {
    if (_cbinfo.IsConstructCall()) {
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
    } else {
      return nullptr;
    }
  }


napi_status napi_delete_element(napi_env env,
                                napi_value object,
                                uint32_t index,
                                bool* result) {
  NAPI_PREAMBLE(env);

  v8::Local<v8::Context> context = env->context();
  v8::Local<v8::Object> obj;

  CHECK_TO_OBJECT(env, context, obj, object);
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);

  if (result != nullptr)
    *result = delete_maybe.FromMaybe(false);

  return GET_RETURN_STATUS(env);
}


napi_status napi_get_new_target(napi_env env,
                                napi_callback_info cbinfo,
                                napi_value* result) {
  CHECK_ENV(env);
  CHECK_ARG(env, cbinfo);
  CHECK_ARG(env, result);

  v8impl::CallbackWrapper* info =
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);

  *result = info->GetNewTarget();
  return napi_clear_last_error(env);
}


  static inline Reference* New(napi_env env,
                             v8::Local<v8::Value> value,
                             uint32_t initial_refcount,
                             bool delete_self,
                             napi_finalize finalize_callback = nullptr,
                             void* finalize_data = nullptr,
                             void* finalize_hint = nullptr) {
    return new Reference(env,
                         value,
                         initial_refcount,
                         delete_self,
                         finalize_callback,
                         finalize_data,
                         finalize_hint);
  }


  inline v8::Local<v8::Value> Get() {
    if (_persistent.IsEmpty()) {
      return v8::Local<v8::Value>();
    } else {
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
    }
  }


V8NameFromPropertyDescriptor(napi_env env,
                             const napi_property_descriptor* p,
                             v8::Local<v8::Name>* result) {
  if (p->utf8name != nullptr) {
    CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
  } else {
    v8::Local<v8::Value> property_value =
      v8impl::V8LocalValueFromJsValue(p->name);

    RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
    *result = property_value.As<v8::Name>();
  }

  return napi_ok;
}


static napi_value TestUtf8(napi_env env, napi_callback_info info) {
  size_t argc = 1;
  napi_value args[1];
  NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));

  NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");

  napi_valuetype valuetype;
  NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));

  NAPI_ASSERT(env, valuetype == napi_string,
      "Wrong type of argment. Expects a string.");

  char buffer[128];
  size_t buffer_size = 128;
  size_t copied;

  NAPI_CALL(env,
      napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &copied));

  napi_value output;
  NAPI_CALL(env, napi_create_string_utf8(env, buffer, copied, &output));

  return output;
}


napi_value GetNewTarget() override { return nullptr; }


napi_status napi_create_uint32(napi_env env,
                               uint32_t value,
                               napi_value* result) {
  CHECK_ENV(env);
  CHECK_ARG(env, result);

  *result = v8impl::JsValueFromV8LocalValue(
      v8::Integer::NewFromUnsigned(env->isolate, value));

  return napi_clear_last_error(env);
}


napi_status napi_get_dataview_info(napi_env env,
                                   napi_value dataview,
                                   size_t* byte_length,
                                   void** data,
                                   napi_value* arraybuffer,
                                   size_t* byte_offset) {
  CHECK_ENV(env);
  CHECK_ARG(env, dataview);

  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);

  v8::Local<v8::DataView> array = value.As<v8::DataView>();

  if (byte_length != nullptr) {
    *byte_length = array->ByteLength();
  }

  v8::Local<v8::ArrayBuffer> buffer;
  if (data != nullptr || arraybuffer != nullptr) {
    // Calling Buffer() may have the side effect of allocating the buffer,
    // so only do this when it’s needed.
    buffer = array->Buffer();
  }

  if (data != nullptr) {
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
            array->ByteOffset();
  }

  if (arraybuffer != nullptr) {
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
  }

  if (byte_offset != nullptr) {
    *byte_offset = array->ByteOffset();
  }

  return napi_clear_last_error(env);
}


napi_status napi_is_date(napi_env env,
                         napi_value value,
                         bool* is_date) {
  CHECK_ENV(env);
  CHECK_ARG(env, value);
  CHECK_ARG(env, is_date);

  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();

  return napi_clear_last_error(env);
}


  static void SecondPassCallback(const v8::WeakCallbackInfo<Reference>& data) {
    data.GetParameter()->Finalize();
  }


static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context,
                                               const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
	wStream* s;
	CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle;
	if (lockClipboardData->msgType != CB_LOCK_CLIPDATA)
		WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__,
		          lockClipboardData->msgType);

	s = cliprdr_packet_lock_clipdata_new(lockClipboardData);
	if (!s)
	{
		WLog_ERR(TAG, "cliprdr_packet_lock_clipdata_new failed!");
		return ERROR_INTERNAL_ERROR;
	}

	WLog_DBG(TAG, "ServerLockClipboardData: clipDataId: 0x%08" PRIX32 "",
	         lockClipboardData->clipDataId);
	return cliprdr_server_packet_send(cliprdr, s);
}


static UINT cliprdr_server_receive_format_data_response(CliprdrServerContext* context, wStream* s,
                                                        const CLIPRDR_HEADER* header)
{
	CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
	UINT error = CHANNEL_RC_OK;

	WLog_DBG(TAG, "CliprdrClientFormatDataResponse");
	formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
	formatDataResponse.msgFlags = header->msgFlags;
	formatDataResponse.dataLen = header->dataLen;

	if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
		return error;

	IFCALLRET(context->ClientFormatDataResponse, error, context, &formatDataResponse);

	if (error)
		WLog_ERR(TAG, "ClientFormatDataResponse failed with error %" PRIu32 "!", error);

	return error;
}


void cliprdr_server_context_free(CliprdrServerContext* context)
{
	CliprdrServerPrivate* cliprdr;

	if (!context)
		return;

	cliprdr = (CliprdrServerPrivate*)context->handle;

	if (cliprdr)
	{
		Stream_Free(cliprdr->s, TRUE);
		free(cliprdr->temporaryDirectory);
	}

	free(context->handle);
	free(context);
}


void VDir::Init(VDir* pDir, VMem *p)
{
    int index;

    pMem = p;
    if (pDir) {
	for (index = 0; index < driveCount; ++index) {
	    SetDirW(pDir->GetDirW(index), index);
	}
	nDefault = pDir->GetDefault();
    }
    else {
	int bSave = bManageDirectory;
	DWORD driveBits = GetLogicalDrives();

	bManageDirectory = 0;
        WCHAR szBuffer[MAX_PATH*driveCount];
        if (GetLogicalDriveStringsW(sizeof(szBuffer), szBuffer)) {
            WCHAR* pEnv = GetEnvironmentStringsW();
            WCHAR* ptr = szBuffer;
            for (index = 0; index < driveCount; ++index) {
                if (driveBits & (1<<index)) {
                    ptr += SetDirW(ptr, index) + 1;
                    FromEnvW(pEnv, index);
                }
            }
            FreeEnvironmentStringsW(pEnv);
        }
        SetDefaultW(L".");
	bManageDirectory = bSave;
  }
}


int VDir::SetDirW(WCHAR const *pPath, int index)
{
    WCHAR chr, *ptr;
    int length = 0;
    if (index < driveCount && pPath != NULL) {
	length = wcslen(pPath);
	pMem->Free(dirTableW[index]);
	ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2);
	if (ptr != NULL) {
            char *ansi;
	    wcscpy(ptr, pPath);
	    ptr += length-1;
	    chr = *ptr++;
	    if (chr != '\\' && chr != '/') {
		*ptr++ = '\\';
		*ptr = '\0';
	    }
            ansi = win32_ansipath(dirTableW[index]);
	    length = strlen(ansi);
	    pMem->Free(dirTableA[index]);
	    dirTableA[index] = (char*)pMem->Malloc(length+1);
	    if (dirTableA[index] != NULL) {
		strcpy(dirTableA[index], ansi);
	    }
            win32_free(ansi);
	}
    }

    if(bManageDirectory)
	::SetCurrentDirectoryW(pPath);

    return length;
}


static void ntlmssp_append_string(buffer_t *buf, size_t buffer_offset,
				  const char *str, bool unicode)
{
	struct ntlmssp_buffer buffer;
	unsigned int length;

	write_le32(&buffer.offset, buf->used);

	length = append_string(buf, str, FALSE, unicode);

	write_le16(&buffer.length, length);
	write_le16(&buffer.space, length);
	buffer_write(buf, buffer_offset, &buffer, sizeof(buffer));
}


static struct auth_request *mech_rpa_auth_new(void)
{
	struct rpa_auth_request *request;
	pool_t pool;

	pool = pool_alloconly_create(MEMPOOL_GROWING"rpa_auth_request", 2048);
	request = p_new(pool, struct rpa_auth_request, 1);
	request->pool = pool;
	request->phase = 0;

	request->auth_request.pool = pool;
	return &request->auth_request;
}


display_get_params(gx_device * dev, gs_param_list * plist)
{
    gx_device_display *ddev = (gx_device_display *) dev;
    int code;
    gs_param_string dhandle;
    int idx;
    int val;
    int i = 0;
    size_t dptr;
    char buf[64];

    idx = ((int)sizeof(size_t)) * 8 - 4;
    buf[i++] = '1';
    buf[i++] = '6';
    buf[i++] = '#';
    dptr = (size_t)(ddev->pHandle);
    while (idx >= 0) {
        val = (int)(dptr >> idx) & 0xf;
        if (val <= 9)
            buf[i++] = '0' + val;
        else
            buf[i++] = 'a' - 10 + val;
        idx -= 4;
    }
    buf[i] = '\0';

    param_string_from_transient_string(dhandle, buf);

    code = gx_default_get_params(dev, plist);
    (void)(code < 0 ||
        (code = param_write_string(plist,
            "DisplayHandle", &dhandle)) < 0 ||
        (code = param_write_int(plist,
            "DisplayFormat", &ddev->nFormat)) < 0 ||
        (code = param_write_float(plist,
            "DisplayResolution", &ddev->HWResolution[1])) < 0);
    if (code >= 0 &&
        (ddev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)
        code = devn_get_params(dev, plist, &ddev->devn_params,
                &ddev->equiv_cmyk_colors);
    return code;
}


display_set_separations(gx_device_display *dev)
{
    if (((dev->nFormat & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION) &&
        (dev->callback->version_major > DISPLAY_VERSION_MAJOR_V1) &&
        (dev->callback->display_separation != NULL)) {
        /* Tell the client about the separation to composite mapping */
        char name[64];
        int num_spot = dev->devn_params.separations.num_separations;
        int num_std_colorants = dev->devn_params.num_std_colorant_names;
        int num_comp = num_std_colorants + num_spot;
        int comp_map[GX_DEVICE_COLOR_MAX_COMPONENTS];
        int comp_num;
        int sep_num;
        int sep_name_size;
        unsigned int c, m, y, k;

        /* Map the separation numbers to component numbers */
        memset(comp_map, 0, sizeof(comp_map));
        for (sep_num = 0; sep_num < num_comp; sep_num++) {
            comp_num = dev->devn_params.separation_order_map[sep_num];
            if (comp_num >= 0 && comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS)
                comp_map[comp_num] = sep_num;
        }
        /* For each component, tell the client the separation mapping */
        for (comp_num = 0; comp_num < num_comp; comp_num++) {
            c = y = m = k = 0;
            sep_num = comp_map[comp_num];
            /* Get the CMYK equivalent */
            if (sep_num < dev->devn_params.num_std_colorant_names) {
                sep_name_size =
                    strlen(dev->devn_params.std_colorant_names[sep_num]);
                if (sep_name_size > sizeof(name)-2)
                    sep_name_size = sizeof(name)-1;
                memcpy(name, dev->devn_params.std_colorant_names[sep_num],
                    sep_name_size);
                name[sep_name_size] = '\0';
                switch (sep_num) {
                    case 0: c = 65535; break;
                    case 1: m = 65535; break;
                    case 2: y = 65535; break;
                    case 3: k = 65535; break;
                }
            }
            else {
                sep_num -= dev->devn_params.num_std_colorant_names;
                sep_name_size =
                    dev->devn_params.separations.names[sep_num].size;
                if (sep_name_size > sizeof(name)-2)
                    sep_name_size = sizeof(name)-1;
                memcpy(name, dev->devn_params.separations.names[sep_num].data,
                    sep_name_size);
                name[sep_name_size] = '\0';
                if (dev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
                    c = dev->equiv_cmyk_colors.color[sep_num].c
                           * 65535 / frac_1;
                    m = dev->equiv_cmyk_colors.color[sep_num].m
                           * 65535 / frac_1;
                    y = dev->equiv_cmyk_colors.color[sep_num].y
                           * 65535 / frac_1;
                    k = dev->equiv_cmyk_colors.color[sep_num].k
                           * 65535 / frac_1;
                }
            }
            while(dev->parent)
                dev = (gx_device_display *)dev->parent;

            (*dev->callback->display_separation)(dev->pHandle, dev,
                comp_num, name,
                (unsigned short)c, (unsigned short)m,
                (unsigned short)y, (unsigned short)k);
        }
    }
    return 0;
}


        for (i = 0; i < ddev->devn_params.separations.num_separations; ++i) {
            RELOC_PTR(gx_device_display, devn_params.separations.names[i].data);
        }


display_map_rgb_color_bgr24(gx_device * dev, const gx_color_value cv[])
{
    gx_color_value r = cv[0];
    gx_color_value g = cv[1];
    gx_color_value b = cv[2];
    return (gx_color_value_to_byte(b)<<16) +
           (gx_color_value_to_byte(g)<<8) +
            gx_color_value_to_byte(r);
}


set_cmyk_color_procs(gx_device * pdev,
        dev_t_proc_encode_color((*encode_color), gx_device),
        dev_t_proc_decode_color((*decode_color), gx_device))
{
    set_color_procs(pdev, encode_color, decode_color,
        gx_default_DevCMYK_get_color_mapping_procs,
        gx_default_DevCMYK_get_color_comp_index,
        gx_default_fill_rectangle_hl_color);
}


display_output_page(gx_device * dev, int copies, int flush)
{
    gx_device_display *ddev = (gx_device_display *) dev;
    int code;
    if (ddev->callback == NULL)
        return gs_error_Fatal;
    display_set_separations(ddev);

    while(dev->parent)
        dev = dev->parent;

    code = (*(ddev->callback->display_page))
                        (ddev->pHandle, dev, copies, flush);

    if (code >= 0)
        code = gx_finish_output_page(dev, copies, flush);
    return code;
}


    static int Raw(llhttp_t* p, Args ... args) {
      Parser* parser = ContainerOf(&Parser::parser_, p);
      int rv = (parser->*Member)(std::forward<Args>(args)...);
      if (rv == 0) {
        rv = parser->MaybePause();
      }
      return rv;
    }


void InitializeHttpParser(Local<Object> target,
                          Local<Value> unused,
                          Local<Context> context,
                          void* priv) {
  Environment* env = Environment::GetCurrent(context);
  BindingData* const binding_data =
      env->AddBindingData<BindingData>(context, target);
  if (binding_data == nullptr) return;

  Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
  t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount);
  t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"));

  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"),
         Integer::New(env->isolate(), HTTP_REQUEST));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"),
         Integer::New(env->isolate(), HTTP_RESPONSE));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageBegin"),
         Integer::NewFromUnsigned(env->isolate(), kOnMessageBegin));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"),
         Integer::NewFromUnsigned(env->isolate(), kOnHeaders));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"),
         Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"),
         Integer::NewFromUnsigned(env->isolate(), kOnBody));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"),
         Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
         Integer::NewFromUnsigned(env->isolate(), kOnExecute));
  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"),
         Integer::NewFromUnsigned(env->isolate(), kOnTimeout));

  Local<Array> methods = Array::New(env->isolate());
#define V(num, name, string)                                                  \
    methods->Set(env->context(),                                              \
        num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).Check();
  HTTP_METHOD_MAP(V)
#undef V
  target->Set(env->context(),
              FIXED_ONE_BYTE_STRING(env->isolate(), "methods"),
              methods).Check();

  t->Inherit(AsyncWrap::GetConstructorTemplate(env));
  env->SetProtoMethod(t, "close", Parser::Close);
  env->SetProtoMethod(t, "free", Parser::Free);
  env->SetProtoMethod(t, "execute", Parser::Execute);
  env->SetProtoMethod(t, "finish", Parser::Finish);
  env->SetProtoMethod(t, "initialize", Parser::Initialize);
  env->SetProtoMethod(t, "pause", Parser::Pause<true>);
  env->SetProtoMethod(t, "resume", Parser::Pause<false>);
  env->SetProtoMethod(t, "consume", Parser::Consume);
  env->SetProtoMethod(t, "unconsume", Parser::Unconsume);
  env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer);

  target->Set(env->context(),
              FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
              t->GetFunction(env->context()).ToLocalChecked()).Check();
}


  static void Initialize(const FunctionCallbackInfo<Value>& args) {
    Environment* env = Environment::GetCurrent(args);
    bool lenient = args[3]->IsTrue();

    uint64_t max_http_header_size = 0;
    uint64_t headers_timeout = 0;

    CHECK(args[0]->IsInt32());
    CHECK(args[1]->IsObject());

    if (args.Length() > 2) {
      CHECK(args[2]->IsNumber());
      max_http_header_size = args[2].As<Number>()->Value();
    }
    if (max_http_header_size == 0) {
      max_http_header_size = env->options()->max_http_header_size;
    }

    if (args.Length() > 4) {
      CHECK(args[4]->IsInt32());
      headers_timeout = args[4].As<Number>()->Value();
    }

    llhttp_type_t type =
        static_cast<llhttp_type_t>(args[0].As<Int32>()->Value());

    CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
    Parser* parser;
    ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
    // Should always be called from the same context.
    CHECK_EQ(env, parser->env());

    AsyncWrap::ProviderType provider =
        (type == HTTP_REQUEST ?
            AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE
            : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST);

    parser->set_provider_type(provider);
    parser->AsyncReset(args[1].As<Object>());
    parser->Init(type, max_http_header_size, lenient, headers_timeout);
  }


  Local<Array> CreateHeaders() {
    // There could be extra entries but the max size should be fixed
    Local<Value> headers_v[kMaxHeaderFieldsCount * 2];

    for (size_t i = 0; i < num_values_; ++i) {
      headers_v[i * 2] = fields_[i].ToString(env());
      headers_v[i * 2 + 1] = values_[i].ToTrimmedString(env());
    }

    return Array::New(env()->isolate(), headers_v, num_values_ * 2);
  }


  BindingData(Environment* env, Local<Object> obj)
      : BaseObject(env, obj) {}


  void Reset() {
    if (on_heap_) {
      delete[] str_;
      on_heap_ = false;
    }

    str_ = nullptr;
    size_ = 0;
  }


do_line()
{
    /* Line continuation has already been handled by read_line() */
    char *inlptr;

    /* Expand any string variables in the current input line */
    string_expand_macros();

    /* Skip leading whitespace */
    inlptr = gp_input_line;
    while (isspace((unsigned char) *inlptr))
	inlptr++;

    /* Leading '!' indicates a shell command that bypasses normal gnuplot
     * tokenization and parsing.  This doesn't work inside a bracketed clause.
     */
    if (is_system(*inlptr)) {
	do_system(inlptr + 1);
	return (0);
    }

    /* Strip off trailing comment */
    FPRINTF((stderr,"doline( \"%s\" )\n", gp_input_line));
    if (strchr(inlptr, '#')) {
	num_tokens = scanner(&gp_input_line, &gp_input_line_len);
	if (gp_input_line[token[num_tokens].start_index] == '#')
	    gp_input_line[token[num_tokens].start_index] = NUL;
    }

    if (inlptr != gp_input_line) {
	/* If there was leading whitespace, copy the actual
	 * command string to the front. use memmove() because
	 * source and target may overlap */
	memmove(gp_input_line, inlptr, strlen(inlptr));
	/* Terminate resulting string */
	gp_input_line[strlen(inlptr)] = NUL;
    }
    FPRINTF((stderr, "  echo: \"%s\"\n", gp_input_line));

    num_tokens = scanner(&gp_input_line, &gp_input_line_len);

    /*
     * Expand line if necessary to contain a complete bracketed clause {...}
     * Insert a ';' after current line and append the next input line.
     * NB: This may leave an "else" condition on the next line.
     */
    if (curly_brace_count < 0)
	int_error(NO_CARET,"Unexpected }");

    while (curly_brace_count > 0) {
	if (lf_head && lf_head->depth > 0) {
	    /* This catches the case that we are inside a "load foo" operation
	     * and therefore requesting interactive input is not an option.
	     * FIXME: or is it?
	     */
	    int_error(NO_CARET, "Syntax error: missing block terminator }");
	}
	else if (interactive || noinputfiles) {
	    /* If we are really in interactive mode and there are unterminated blocks,
	     * then we want to display a "more>" prompt to get the rest of the block.
	     * However, there are two more cases that must be dealt here:
	     * One is when commands are piped to gnuplot - on the command line,
	     * the other is when commands are piped to gnuplot which is opened
	     * as a slave process. The test for noinputfiles is for the latter case.
	     * If we didn't have that test here, unterminated blocks sent via a pipe
	     * would trigger the error message in the else branch below. */
	    int retval;
	    strcat(gp_input_line,";");
	    retval = read_line("more> ", strlen(gp_input_line));
	    if (retval)
		int_error(NO_CARET, "Syntax error: missing block terminator }");
	    /* Expand any string variables in the current input line */
	    string_expand_macros();

	    num_tokens = scanner(&gp_input_line, &gp_input_line_len);
	    if (gp_input_line[token[num_tokens].start_index] == '#')
		gp_input_line[token[num_tokens].start_index] = NUL;
	}
	else {
	    /* Non-interactive mode here means that we got a string from -e.
	     * Having curly_brace_count > 0 means that there are at least one
	     * unterminated blocks in the string.
	     * Likely user error, so we die with an error message. */
	    int_error(NO_CARET, "Syntax error: missing block terminator }");
	}
    }

    c_token = 0;
    while (c_token < num_tokens) {
	command();
	if (command_exit_requested) {
	    command_exit_requested = 0;	/* yes this is necessary */
	    return 1;
	}
	if (iteration_early_exit()) {
	    c_token = num_tokens;
	    break;
	}
	if (c_token < num_tokens) {	/* something after command */
	    if (equals(c_token, ";")) {
		c_token++;
	    } else if (equals(c_token, "{")) {
		begin_clause();
	    } else if (equals(c_token, "}")) {
		end_clause();
	    } else
		int_error(c_token, "unexpected or unrecognized token: %s",
		    token_to_string(c_token));
	}
    }

    /* This check allows event handling inside load/eval/while statements */
    check_for_mouse_events();
    return (0);
}


expand_1level_macros()
{
    TBOOLEAN in_squote = FALSE;
    TBOOLEAN in_dquote = FALSE;
    TBOOLEAN after_backslash = FALSE;
    TBOOLEAN in_comment= FALSE;
    int   len;
    int   o = 0;
    int   nfound = 0;
    char *c;
    char *temp_string;
    char  temp_char;
    char *m;
    struct udvt_entry *udv;

    /* Most lines have no macros */
    if (!strchr(gp_input_line,'@'))
	return(0);

    temp_string = gp_alloc(gp_input_line_len,"string variable");
    len = strlen(gp_input_line);
    if (len >= gp_input_line_len) len = gp_input_line_len-1;
    strncpy(temp_string,gp_input_line,len);
    temp_string[len] = '\0';

    for (c=temp_string; len && c && *c; c++, len--) {
	switch (*c) {
	case '@':	/* The only tricky bit */
		if (!in_squote && !in_dquote && !in_comment && isalpha((unsigned char)c[1])) {
		    /* Isolate the udv key as a null-terminated substring */
		    m = ++c;
		    while (isalnum((unsigned char )*c) || (*c=='_')) c++;
		    temp_char = *c; *c = '\0';
		    /* Look up the key and restore the original following char */
		    udv = get_udv_by_name(m);
		    if (udv && udv->udv_value.type == STRING) {
			nfound++;
			m = udv->udv_value.v.string_val;
			FPRINTF((stderr,"Replacing @%s with \"%s\"\n",udv->udv_name,m));
			while (strlen(m) + o + len > gp_input_line_len)
			    extend_input_line();
			while (*m)
			    gp_input_line[o++] = (*m++);
		    } else {
			int_warn( NO_CARET, "%s is not a string variable",m);
		    }
		    *c-- = temp_char;
		} else
		    COPY_CHAR;
		break;

	case '"':
		if (!after_backslash)
		    in_dquote = !in_dquote;
		COPY_CHAR; break;
	case '\'':
		in_squote = !in_squote;
		COPY_CHAR; break;
	case '\\':
		if (in_dquote)
		    after_backslash = !after_backslash;
		gp_input_line[o++] = *c; break;
	case '#':
		if (!in_squote && !in_dquote)
		    in_comment = TRUE;
	default :
		COPY_CHAR; break;
	}
    }
    gp_input_line[o] = '\0';
    free(temp_string);

    if (nfound)
	FPRINTF((stderr,
		 "After string substitution command line is:\n\t%s\n",
		 gp_input_line));

    return(nfound);
}


restore_prompt()
{
    if (interactive) {
#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
#  if !defined(MISSING_RL_FORCED_UPDATE_DISPLAY)
	rl_forced_update_display();
#  else
	rl_redisplay();
#  endif
#else
	fputs(PROMPT, stderr);
	fflush(stderr);
#endif
    }
}


clause_reset_after_error()
{
    if (clause_depth)
	FPRINTF((stderr,"CLAUSE RESET after error at depth %d\n",clause_depth));
    clause_depth = 0;
    iteration_depth = 0;
}


save_command()
{
    FILE *fp;
    char *save_file = NULL;
    TBOOLEAN append = FALSE;
    int what;

    c_token++;
    what = lookup_table(&save_tbl[0], c_token);

    switch (what) {
	case SAVE_FUNCS:
	case SAVE_SET:
	case SAVE_TERMINAL:
	case SAVE_VARS:
	case SAVE_FIT:
	case SAVE_DATABLOCKS:
	    c_token++;
	    break;
	default:
	    break;
    }

    save_file = try_to_get_string();
    if (!save_file)
	int_error(c_token, "expecting filename");
    if (equals(c_token, "append")) {
	append = TRUE;
	c_token++;
    }
#ifdef PIPES
    if (save_file[0]=='|') {
	restrict_popen();
	fp = popen(save_file+1,"w");
    } else
#endif
    {
    gp_expand_tilde(&save_file);
#ifdef _WIN32
    fp = !strcmp(save_file,"-") ? stdout
	: loadpath_fopen(save_file, append?"a":"w");
#else
    fp = !strcmp(save_file,"-") ? stdout
	: fopen(save_file, append?"a":"w");
#endif
    }

    if (!fp)
	os_error(c_token, "Cannot open save file");

    switch (what) {
    case SAVE_FUNCS:
	    save_functions(fp);
	break;
    case SAVE_SET:
	    save_set(fp);
	break;
    case SAVE_TERMINAL:
	    save_term(fp);
	break;
    case SAVE_VARS:
	    save_variables(fp);
	break;
    case SAVE_FIT:
	    save_fit(fp);
	break;
    case SAVE_DATABLOCKS:
	    save_datablocks(fp);
	break;
    default:
	    save_all(fp);
    }

    if (stdout != fp) {
#ifdef PIPES
	if (save_file[0] == '|')
	    (void) pclose(fp);
	else
#endif
	    (void) fclose(fp);
    }

    free(save_file);
}


replot_command()
{
    if (!*replot_line)
	int_error(c_token, "no previous plot");

    if (volatile_data && (refresh_ok != E_REFRESH_NOT_OK) && !replot_disabled) {
	FPRINTF((stderr,"volatile_data %d refresh_ok %d plotted_data_from_stdin %d\n",
		volatile_data, refresh_ok, plotted_data_from_stdin));
	refresh_command();
	return;
    }

    /* Disable replot for some reason; currently used by the mouse/hotkey
       capable terminals to avoid replotting when some data come from stdin,
       i.e. when  plotted_data_from_stdin==1  after plot "-".
    */
    if (replot_disabled) {
	replot_disabled = FALSE;
	bail_to_command_line(); /* be silent --- don't mess the screen */
    }
    if (!term) /* unknown terminal */
	int_error(c_token, "use 'set term' to set terminal type first");

    c_token++;
    SET_CURSOR_WAIT;
    if (term->flags & TERM_INIT_ON_REPLOT)
	term->init();
    replotrequest();
    SET_CURSOR_ARROW;
}