static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
{
    switch (s->vga.sr_index) {
    case 0x00:			// Standard VGA
    case 0x01:			// Standard VGA
    case 0x02:			// Standard VGA
    case 0x03:			// Standard VGA
    case 0x04:			// Standard VGA
	s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index];
	if (s->vga.sr_index == 1)
            s->vga.update_retrace_info(&s->vga);
        break;
    case 0x06:			// Unlock Cirrus extensions
	val &= 0x17;
	if (val == 0x12) {
	    s->vga.sr[s->vga.sr_index] = 0x12;
	} else {
	    s->vga.sr[s->vga.sr_index] = 0x0f;
	}
	break;
    case 0x10:
    case 0x30:
    case 0x50:
    case 0x70:			// Graphics Cursor X
    case 0x90:
    case 0xb0:
    case 0xd0:
    case 0xf0:			// Graphics Cursor X
	s->vga.sr[0x10] = val;
        s->vga.hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
	break;
    case 0x11:
    case 0x31:
    case 0x51:
    case 0x71:			// Graphics Cursor Y
    case 0x91:
    case 0xb1:
    case 0xd1:
    case 0xf1:			// Graphics Cursor Y
	s->vga.sr[0x11] = val;
        s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
	break;
    case 0x07:			// Extended Sequencer Mode
    cirrus_update_memory_access(s);
    case 0x08:			// EEPROM Control
    case 0x09:			// Scratch Register 0
    case 0x0a:			// Scratch Register 1
    case 0x0b:			// VCLK 0
    case 0x0c:			// VCLK 1
    case 0x0d:			// VCLK 2
    case 0x0e:			// VCLK 3
    case 0x0f:			// DRAM Control
    case 0x13:			// Graphics Cursor Pattern Address
    case 0x14:			// Scratch Register 2
    case 0x15:			// Scratch Register 3
    case 0x16:			// Performance Tuning Register
    case 0x18:			// Signature Generator Control
    case 0x19:			// Signature Generator Result
    case 0x1a:			// Signature Generator Result
    case 0x1b:			// VCLK 0 Denominator & Post
    case 0x1c:			// VCLK 1 Denominator & Post
    case 0x1d:			// VCLK 2 Denominator & Post
    case 0x1e:			// VCLK 3 Denominator & Post
    case 0x1f:			// BIOS Write Enable and MCLK select
	s->vga.sr[s->vga.sr_index] = val;
#ifdef DEBUG_CIRRUS
	printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
	       s->vga.sr_index, val);
#endif
	break;
    case 0x12:			// Graphics Cursor Attribute
	s->vga.sr[0x12] = val;
        s->vga.force_shadow = !!(val & CIRRUS_CURSOR_SHOW);
#ifdef DEBUG_CIRRUS
        printf("cirrus: cursor ctl SR12=%02x (force shadow: %d)\n",
               val, s->vga.force_shadow);
#endif
        break;
    case 0x17:			// Configuration Readback and Extended Control
	s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
                                   | (val & 0xc7);
        cirrus_update_memory_access(s);
        break;
    default:
#ifdef DEBUG_CIRRUS
	printf("cirrus: outport sr_index %02x, sr_value %02x\n",
               s->vga.sr_index, val);
#endif
	break;
    }
}


static void cirrus_vga_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->realize = pci_cirrus_vga_realize;
    k->romfile = VGABIOS_CIRRUS_FILENAME;
    k->vendor_id = PCI_VENDOR_ID_CIRRUS;
    k->device_id = CIRRUS_ID_CLGD5446;
    k->class_id = PCI_CLASS_DISPLAY_VGA;
    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    dc->desc = "Cirrus CLGD 54xx VGA";
    dc->vmsd = &vmstate_pci_cirrus_vga;
    dc->props = pci_vga_cirrus_properties;
    dc->hotpluggable = false;
}


static void map_linear_vram(CirrusVGAState *s)
{
    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
        s->linear_vram = true;
        memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
    }
    map_linear_vram_bank(s, 0);
    map_linear_vram_bank(s, 1);
}


static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
{
    int value = 0xff;

    switch (address) {
    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x00);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x10);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
	value = cirrus_vga_read_gr(s, 0x12);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
	value = cirrus_vga_read_gr(s, 0x14);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x01);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x11);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
	value = cirrus_vga_read_gr(s, 0x13);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
	value = cirrus_vga_read_gr(s, 0x15);
	break;
    case (CIRRUS_MMIO_BLTWIDTH + 0):
	value = cirrus_vga_read_gr(s, 0x20);
	break;
    case (CIRRUS_MMIO_BLTWIDTH + 1):
	value = cirrus_vga_read_gr(s, 0x21);
	break;
    case (CIRRUS_MMIO_BLTHEIGHT + 0):
	value = cirrus_vga_read_gr(s, 0x22);
	break;
    case (CIRRUS_MMIO_BLTHEIGHT + 1):
	value = cirrus_vga_read_gr(s, 0x23);
	break;
    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
	value = cirrus_vga_read_gr(s, 0x24);
	break;
    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
	value = cirrus_vga_read_gr(s, 0x25);
	break;
    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
	value = cirrus_vga_read_gr(s, 0x26);
	break;
    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
	value = cirrus_vga_read_gr(s, 0x27);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 0):
	value = cirrus_vga_read_gr(s, 0x28);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 1):
	value = cirrus_vga_read_gr(s, 0x29);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 2):
	value = cirrus_vga_read_gr(s, 0x2a);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 0):
	value = cirrus_vga_read_gr(s, 0x2c);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 1):
	value = cirrus_vga_read_gr(s, 0x2d);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 2):
	value = cirrus_vga_read_gr(s, 0x2e);
	break;
    case CIRRUS_MMIO_BLTWRITEMASK:
	value = cirrus_vga_read_gr(s, 0x2f);
	break;
    case CIRRUS_MMIO_BLTMODE:
	value = cirrus_vga_read_gr(s, 0x30);
	break;
    case CIRRUS_MMIO_BLTROP:
	value = cirrus_vga_read_gr(s, 0x32);
	break;
    case CIRRUS_MMIO_BLTMODEEXT:
	value = cirrus_vga_read_gr(s, 0x33);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x34);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x35);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
	value = cirrus_vga_read_gr(s, 0x38);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
	value = cirrus_vga_read_gr(s, 0x39);
	break;
    case CIRRUS_MMIO_BLTSTATUS:
	value = cirrus_vga_read_gr(s, 0x31);
	break;
    default:
#ifdef DEBUG_CIRRUS
	printf("cirrus: mmio read - address 0x%04x\n", address);
#endif
	break;
    }

    trace_vga_cirrus_write_blt(address, value);
    return (uint8_t) value;
}


static inline uint8_t cirrus_src(CirrusVGAState *s, uint32_t srcaddr)
{
    if (s->cirrus_srccounter) {
        /* cputovideo */
        return s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1)];
    } else {
        /* videotovideo */
        return s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask];
    }
}


static inline uint16_t cirrus_src16(CirrusVGAState *s, uint32_t srcaddr)
{
    uint16_t *src;

    if (s->cirrus_srccounter) {
        /* cputovideo */
        src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~1];
    } else {
        /* videotovideo */
        src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~1];
    }
    return *src;
}


static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
{
    return cirrus_bitblt_common_patterncopy(s);
}


static ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
                                       const char *name)
{
    char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
    int ret;

    ret = lremovexattr(proc_path, name);
    g_free(proc_path);
    return ret;
}


change_env (timezone_t tz)
{
  if (setenv_TZ (tz->tz_is_set ? tz->abbrs : NULL) != 0)
    return false;
  tzset ();
  return true;
}


set_tz (timezone_t tz)
{
  char *env_tz = getenv_TZ ();
  if (env_tz
      ? tz->tz_is_set && strcmp (tz->abbrs, env_tz) == 0
      : !tz->tz_is_set)
    return local_tz;
  else
    {
      timezone_t old_tz = tzalloc (env_tz);
      if (!old_tz)
        return old_tz;
      if (! change_env (tz))
        {
          int saved_errno = errno;
          tzfree (old_tz);
          errno = saved_errno;
          return NULL;
        }
      return old_tz;
    }
}


static int macsec_notify(struct notifier_block *this, unsigned long event,
			 void *ptr)
{
	struct net_device *real_dev = netdev_notifier_info_to_dev(ptr);
	LIST_HEAD(head);

	if (!is_macsec_master(real_dev))
		return NOTIFY_DONE;

	switch (event) {
	case NETDEV_UNREGISTER: {
		struct macsec_dev *m, *n;
		struct macsec_rxh_data *rxd;

		rxd = macsec_data_rtnl(real_dev);
		list_for_each_entry_safe(m, n, &rxd->secys, secys) {
			macsec_common_dellink(m->secy.netdev, &head);
		}

		netdev_rx_handler_unregister(real_dev);
		kfree(rxd);

		unregister_netdevice_many(&head);
		break;
	}
	case NETDEV_CHANGEMTU: {
		struct macsec_dev *m;
		struct macsec_rxh_data *rxd;

		rxd = macsec_data_rtnl(real_dev);
		list_for_each_entry(m, &rxd->secys, secys) {
			struct net_device *dev = m->secy.netdev;
			unsigned int mtu = real_dev->mtu - (m->secy.icv_len +
							    macsec_extra_len(true));

			if (dev->mtu > mtu)
				dev_set_mtu(dev, mtu);
		}
	}
	}

	return NOTIFY_OK;
}


static bool is_macsec_master(struct net_device *dev)
{
	return rcu_access_pointer(dev->rx_handler) == macsec_handle_frame;
}


static void macsec_dellink(struct net_device *dev, struct list_head *head)
{
	struct macsec_dev *macsec = macsec_priv(dev);
	struct net_device *real_dev = macsec->real_dev;
	struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);

	macsec_common_dellink(dev, head);

	if (list_empty(&rxd->secys)) {
		netdev_rx_handler_unregister(real_dev);
		kfree(rxd);
	}
}


static void macsec_encrypt_done(struct crypto_async_request *base, int err)
{
	struct sk_buff *skb = base->data;
	struct net_device *dev = skb->dev;
	struct macsec_dev *macsec = macsec_priv(dev);
	struct macsec_tx_sa *sa = macsec_skb_cb(skb)->tx_sa;
	int len, ret;

	aead_request_free(macsec_skb_cb(skb)->req);

	rcu_read_lock_bh();
	macsec_encrypt_finish(skb, dev);
	macsec_count_tx(skb, &macsec->secy.tx_sc, macsec_skb_cb(skb)->tx_sa);
	len = skb->len;
	ret = dev_queue_xmit(skb);
	count_tx(dev, ret, len);
	rcu_read_unlock_bh();

	macsec_txsa_put(sa);
	dev_put(dev);
}


cr_input_ref (CRInput * a_this)
{
        g_return_if_fail (a_this && PRIVATE (a_this));

        PRIVATE (a_this)->ref_count++;
}


cr_input_get_parsing_location (CRInput const *a_this,
                               CRParsingLocation *a_loc)
{
        g_return_val_if_fail (a_this
                              && PRIVATE (a_this)
                              && a_loc,
                              CR_BAD_PARAM_ERROR) ;

        a_loc->line = PRIVATE (a_this)->line ;
        a_loc->column = PRIVATE (a_this)->col ;
        if (PRIVATE (a_this)->next_byte_index) {
                a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
        } else {
                a_loc->byte_offset = PRIVATE (a_this)->next_byte_index  ;
        }
        return CR_OK ;
}


cr_input_get_line_num (CRInput const * a_this, glong * a_line_num)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this)
                              && a_line_num, CR_BAD_PARAM_ERROR);

        *a_line_num = PRIVATE (a_this)->line;

        return CR_OK;
}


static int uint64_mul_overflow(uint64_t a, uint64_t b, uint64_t *res)
{
    *res = a * b;
    return (a > UINT64_MAX / b);
}


CLEAR_MARKS_PROC(aos_clear_marks)
{   aos_state_t *const pptr = vptr;

    r_clear_attrs(&pptr->blocks, l_mark);
}


static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,
					  u8 *_n_elem,
					  u8 max_n_elem,
					  size_t max_elem_size,
					  const __be32 **_xdr,
					  unsigned int *_toklen)
{
	struct krb5_tagged_data *td;
	const __be32 *xdr = *_xdr;
	unsigned int toklen = *_toklen, n_elem, loop;
	int ret;

	/* there must be at least one count */
	if (toklen < 4)
		return -EINVAL;

	_enter(",,%u,%zu,{%x},%u",
	       max_n_elem, max_elem_size, ntohl(xdr[0]), toklen);

	n_elem = ntohl(*xdr++);
	toklen -= 4;
	if (n_elem > max_n_elem)
		return -EINVAL;
	*_n_elem = n_elem;
	if (n_elem > 0) {
		if (toklen <= (n_elem + 1) * 4)
			return -EINVAL;

		_debug("n_elem %d", n_elem);

		td = kcalloc(n_elem, sizeof(struct krb5_tagged_data),
			     GFP_KERNEL);
		if (!td)
			return -ENOMEM;
		*_td = td;

		for (loop = 0; loop < n_elem; loop++) {
			ret = rxrpc_krb5_decode_tagged_data(&td[loop],
							    max_elem_size,
							    &xdr, &toklen);
			if (ret < 0)
				return ret;
		}
	}

	*_xdr = xdr;
	*_toklen = toklen;
	_leave(" = 0 [toklen=%u]", toklen);
	return 0;
}


void Smb4KMountJob::slotStartMount()
{
  QList<Action> actions;
  QMutableListIterator<Smb4KShare *> it(m_shares);

  while (it.hasNext())
  {
    Smb4KShare *share = it.next();
    Action mountAction;

    // Create the mountpoint.
    QString mountpoint;
    mountpoint += Smb4KSettings::mountPrefix().path();
    mountpoint += QDir::separator();
    mountpoint += (Smb4KSettings::forceLowerCaseSubdirs() ? share->hostName().toLower() : share->hostName());
    mountpoint += QDir::separator();

    if (!share->isHomesShare())
    {
      mountpoint += (Smb4KSettings::forceLowerCaseSubdirs() ? share->shareName().toLower() : share->shareName());
    }
    else
    {
      mountpoint += (Smb4KSettings::forceLowerCaseSubdirs() ? share->login().toLower() : share->login());
    }

    // Get the permissions that should be used for creating the
    // mount prefix and all its subdirectories.
    // Please note that the actual permissions of the mount points
    // are determined by the mount utility.
    QFile::Permissions permissions;
    KUrl parentDirectory;

    if (QFile::exists(Smb4KSettings::mountPrefix().path()))
    {
      parentDirectory = Smb4KSettings::mountPrefix();
    }
    else
    {
      KUrl u(Smb4KSettings::mountPrefix());
      parentDirectory = u.upUrl();
    }

    QFile f(parentDirectory.path());
    permissions = f.permissions();

    QDir dir(mountpoint);

    if (!dir.mkpath(dir.path()))
    {
      share->setPath("");
      Smb4KNotification::mkdirFailed(dir);
      return;
    }
    else
    {
      KUrl u(dir.path());

      while (!parentDirectory.equals(u, KUrl::CompareWithoutTrailingSlash))
      {
        QFile(u.path()).setPermissions(permissions);
        u = u.upUrl();
      }
    }

    share->setPath(QDir::cleanPath(mountpoint));

    // Create the mount action.
    if (createMountAction(share, &mountAction))
    {
      connect( mountAction.watcher(), SIGNAL(actionPerformed(ActionReply)),
               this, SLOT(slotActionFinished(ActionReply)) );

      actions << mountAction;
    }
    else
    {
      // The creation of the mount action failed. Remove the
      // mountpoint again.
      dir.rmdir(dir.canonicalPath());
      if (dir.cdUp())
      {
        dir.rmdir(dir.canonicalPath());
      }
      else
      {
        // Do nothing
      }
    }
  }

  if (!actions.isEmpty())
  {
    emit aboutToStart(m_shares);
    Action::executeActions(actions, NULL, "net.sourceforge.smb4k.mounthelper");
  }
  else
  {
    // No aboutToStart() signal should have been emitted,
    // so there is no need to emit a finished() signal.
    emitResult();
  }
}


bool Smb4KMountJob::fillArgs(Smb4KShare *, QMap<QString, QVariant>&)
{
  qWarning() << "Smb4KMountJob::fillArgs() is not implemented!";
  qWarning() << "Mounting under this operating system is not supported...";
  return false;
}


ActionReply Smb4KMountHelper::mount(const QVariantMap &args)
{
  ActionReply reply;

  //
  // Get the mount executable
  //
  const QString mount = findMountExecutable();

  //
  // Check the executable
  //
  if (mount != args["mh_command"].toString())
  {
    // Something weird is going on, bail out.
    reply.setErrorCode(ActionReply::HelperError);
    reply.setErrorDescription(i18n("Wrong executable passed. Bailing out."));
    return reply;
  }
  else
  {
    // Do nothing
  }

  // The mountpoint is a unique and can be used to
  // find the share.
  reply.addData("mh_mountpoint", args["mh_mountpoint"]);

  KProcess proc(this);
  proc.setOutputChannelMode(KProcess::SeparateChannels);
  proc.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
#if defined(Q_OS_LINUX)
  proc.setEnv("PASSWD", args["mh_url"].toUrl().password(), true);
#endif
  // We need this to avoid a translated password prompt.
  proc.setEnv("LANG", "C");
  // If the location of a Kerberos ticket is passed, it needs to
  // be passed to the process environment here.
  if (args.contains("mh_krb5ticket"))
  {
    proc.setEnv("KRB5CCNAME", args["mh_krb5ticket"].toString());
  }
  else
  {
    // Do nothing
  }

  // Set the mount command here.
  QStringList command;
#if defined(Q_OS_LINUX)
  command << mount;
  command << args["mh_unc"].toString();
  command << args["mh_mountpoint"].toString();
  command << args["mh_options"].toStringList();
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
  command << mount;
  command << args["mh_options"].toStringList();
  command << args["mh_unc"].toString();
  command << args["mh_mountpoint"].toString();
#else
  // Do nothing.
#endif
  proc.setProgram(command);

  // Run the mount process.
  proc.start();

  if (proc.waitForStarted(-1))
  {
    bool user_kill = false;

    while (!proc.waitForFinished(10))
    {
      // Check if there is a password prompt. If there is one, pass
      // the password to it.
      QByteArray out = proc.readAllStandardError();

      if (out.startsWith("Password:"))
      {
        proc.write(args["mh_url"].toUrl().password().toUtf8());
        proc.write("\r");
      }
      else
      {
        // Do nothing
      }

      // We want to be able to terminate the process from outside.
      // Thus, we implement a loop that checks periodically, if we
      // need to kill the process.
      if (HelperSupport::isStopped())
      {
        proc.kill();
        user_kill = true;
        break;
      }
      else
      {
        // Do nothing
      }
    }

    if (proc.exitStatus() == KProcess::CrashExit)
    {
      if (!user_kill)
      {
        reply.setErrorCode(ActionReply::HelperError);
        reply.setErrorDescription(i18n("The mount process crashed."));
        return reply;
      }
      else
      {
        // Do nothing
      }
    }
    else
    {
      // Check if there is output on stderr.
      QString stdErr = QString::fromUtf8(proc.readAllStandardError());
      reply.addData("mh_error_message", stdErr.trimmed());
    }
  }
  else
  {
    reply.setErrorCode(ActionReply::HelperError);
    reply.setErrorDescription(i18n("The mount process could not be started."));
  }

  return reply;
}


bool Smb4KGlobal::coreIsInitialized()
{
  return p->coreInitialized;
}


bool Smb4KMountJob::createMountAction(Smb4KShare *share, Action *action)
{
  Q_ASSERT(share);
  Q_ASSERT(action);

  if (!share || !action)
  {
    return false;
  }
  else
  {
    // Do nothing
  }

  // Map that holds the mount command, etc.
  QMap<QString, QVariant> mount_args;

  // Fill the map and create the mountpoint upon success.
  if (!fillArgs(share, mount_args))
  {
    return false;
  }
  else
  {
    // Do nothing
  }

  action->setName("net.sourceforge.smb4k.mounthelper.mount");
  action->setHelperID("net.sourceforge.smb4k.mounthelper");

  // Add the mount arguments (i. e. mount command, options,
  // mountpoint, unc, ...)
  QMapIterator<QString, QVariant> it(mount_args);

  while (it.hasNext())
  {
    it.next();
    action->addArgument(it.key(), it.value());
  }

  if (!share->isHomesShare())
  {
    action->addArgument("mh_url", static_cast<QUrl>(share->url()));
  }
  else
  {
    action->addArgument("mh_url", static_cast<QUrl>(share->homeURL()));
  }

  action->addArgument("mh_workgroup", share->workgroupName());
  action->addArgument("mh_comment", share->comment());
  action->addArgument("mh_ip", share->hostIP());

  // The path to the Kerberos ticket is stored - if it exists - in the
  // KRB5CCNAME environment variable. By default, the ticket is located
  // at /tmp/krb5cc_[uid]. So, if the environment variable does not exist,
  // but the cache file is there, try to use it.
  if (QProcessEnvironment::systemEnvironment().contains("KRB5CCNAME"))
  {
    action->addArgument("mh_krb5ticket", QProcessEnvironment::systemEnvironment().value("KRB5CCNAME", ""));
  }
  else
  {
    QString ticket = QString("/tmp/krb5cc_%1").arg(KUser(KUser::UseRealUserID).uid());

    if (QFile::exists(ticket))
    {
      action->addArgument("mh_krb5ticket", "FILE:"+ticket);
    }
    else
    {
      // Do nothing
    }
  }

  return true;
}


bool Smb4KMountJob::doKill()
{
  Action( "net.sourceforge.smb4k.mounthelper.mount" ).stop();
  return KJob::doKill();
}


Smb4KMountDialog::Smb4KMountDialog( Smb4KShare *share, QWidget *parent )
: KDialog( parent ), m_share( share ), m_valid( true )
{
  setCaption( i18n( "Mount Share" ) );
  setButtons( Ok | Cancel );
  setDefaultButton( Ok );

  setupView();

  connect( this, SIGNAL(okClicked()), SLOT(slotOkClicked()) );
  connect( this, SIGNAL(cancelClicked()), SLOT(slotCancelClicked()) );

  setMinimumWidth( sizeHint().width() > 350 ? sizeHint().width() : 350 );

  KConfigGroup group( Smb4KSettings::self()->config(), "MountDialog" );
  restoreDialogSize( group );

  m_share_input->completionObject()->setItems( group.readEntry( "ShareNameCompletion", QStringList() ) );
  m_ip_input->completionObject()->setItems( group.readEntry( "IPAddressCompletion", QStringList() ) );
  m_workgroup_input->completionObject()->setItems( group.readEntry( "WorkgroupCompletion", QStringList() ) );
}


void Smb4KUnmountJob::start()
{
  m_started = true;

  if ( !m_synchron )
  {
    QTimer::singleShot( 50, this, SLOT(slotStartUnmount()) );
  }
  else
  {
    slotStartUnmount();
  }
}


bool Smb4KGlobal::removeWorkgroup( Smb4KWorkgroup *workgroup )
{
  Q_ASSERT( workgroup );

  bool removed = false;

  mutex.lock();

  int index = p->workgroupsList.indexOf( workgroup );

  if ( index != -1 )
  {
    // The workgroup was found. Remove it.
    delete p->workgroupsList.takeAt( index );
    removed = true;
  }
  else
  {
    // Try harder to find the workgroup.
    Smb4KWorkgroup *wg = findWorkgroup( workgroup->workgroupName() );

    if ( wg )
    {
      index = p->workgroupsList.indexOf( wg );

      if ( index != -1 )
      {
        delete p->workgroupsList.takeAt( index );
        removed = true;
      }
      else
      {
        // Do nothing
      }
    }
    else
    {
      // Do nothing
    }

    delete workgroup;
  }

  mutex.unlock();

  return removed;
}


void Smb4KGlobal::clearWorkgroupsList()
{
  mutex.lock();

  while ( !p->workgroupsList.isEmpty() )
  {
    delete p->workgroupsList.takeFirst();
  }

  mutex.unlock();
}


const QString Smb4KGlobal::winsServer()
{
  QMap<QString,QString> global_opts = p->globalSambaOptions( false );
  QString wins_server;

  if ( global_opts.contains( "wins server" ) )
  {
    wins_server = global_opts.value( "wins server" );
  }
  else
  {
    if ( global_opts.contains( "wins support" ) &&
         (QString::compare( global_opts.value( "wins support" ), "yes", Qt::CaseInsensitive ) == 0 ||
          QString::compare( global_opts.value( "wins support" ), "true", Qt::CaseInsensitive ) == 0) )
    {
      wins_server = "127.0.0.1";
    }
    else
    {
      // Do nothing
    }
  }

  return wins_server;
}


bool Smb4KGlobal::addHost( Smb4KHost *host )
{
  Q_ASSERT( host );

  bool added = false;

  mutex.lock();

  if ( !findHost( host->hostName(), host->workgroupName() ) )
  {
    p->hostsList.append( host );
    added = true;
  }
  else
  {
    // Do nothing
  }

  mutex.unlock();

  return added;
}


void Smb4KGlobal::abortCore()
{
  Smb4KScanner::self()->abortAll();
  Smb4KMounter::self()->abortAll();
  Smb4KPrint::self()->abortAll();
  Smb4KSynchronizer::self()->abortAll();
  Smb4KPreviewer::self()->abortAll();
  Smb4KSearch::self()->abortAll();
}


cr_tknzr_unref (CRTknzr * a_this)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);

        if (PRIVATE (a_this)->ref_count > 0) {
                PRIVATE (a_this)->ref_count--;
        }

        if (PRIVATE (a_this)->ref_count == 0) {
                cr_tknzr_destroy (a_this);
                return TRUE;
        }

        return FALSE;
}


cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this)
                              && PRIVATE (a_this)->input
                              && a_pos, CR_BAD_PARAM_ERROR);

        if (PRIVATE (a_this)->token_cache) {
                cr_input_set_cur_pos (PRIVATE (a_this)->input,
                                      &PRIVATE (a_this)->prev_pos);
                cr_token_destroy (PRIVATE (a_this)->token_cache);
                PRIVATE (a_this)->token_cache = NULL;
        }

        return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos);
}


cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte)
{
        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);

        return cr_input_read_byte (PRIVATE (a_this)->input, a_byte);

}


static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr)
{
	struct sk_buff *skb;
	struct sadb_msg *hdr;

	skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
	if (!skb)
		return -ENOBUFS;

	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
	memcpy(hdr, ihdr, sizeof(struct sadb_msg));
	hdr->sadb_msg_errno = (uint8_t) 0;
	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));

	return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
}


static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c)
{
	struct sk_buff *out_skb;
	struct sadb_msg *out_hdr;
	int hard;
	int hsc;

	hard = c->data.hard;
	if (hard)
		hsc = 2;
	else
		hsc = 1;

	out_skb = pfkey_xfrm_state2msg_expire(x, hsc);
	if (IS_ERR(out_skb))
		return PTR_ERR(out_skb);

	out_hdr = (struct sadb_msg *) out_skb->data;
	out_hdr->sadb_msg_version = PF_KEY_V2;
	out_hdr->sadb_msg_type = SADB_EXPIRE;
	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
	out_hdr->sadb_msg_errno = 0;
	out_hdr->sadb_msg_reserved = 0;
	out_hdr->sadb_msg_seq = 0;
	out_hdr->sadb_msg_pid = 0;

	pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x));
	return 0;
}


static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struct sadb_msg *hdr, int dir)
{
	int err;
	struct sk_buff *out_skb;
	struct sadb_msg *out_hdr;
	err = 0;

	out_skb = pfkey_xfrm_policy2msg_prep(xp);
	if (IS_ERR(out_skb)) {
		err =  PTR_ERR(out_skb);
		goto out;
	}
	err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
	if (err < 0)
		goto out;

	out_hdr = (struct sadb_msg *) out_skb->data;
	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
	out_hdr->sadb_msg_type = hdr->sadb_msg_type;
	out_hdr->sadb_msg_satype = 0;
	out_hdr->sadb_msg_errno = 0;
	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
	pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp));
	err = 0;

out:
	return err;
}


static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
			 const struct sadb_msg *hdr, void * const *ext_hdrs)
{
	int i, len, ret, err = -EINVAL;
	u8 dir;
	struct sadb_address *sa;
	struct sadb_x_kmaddress *kma;
	struct sadb_x_policy *pol;
	struct sadb_x_ipsecrequest *rq;
	struct xfrm_selector sel;
	struct xfrm_migrate m[XFRM_MAX_DEPTH];
	struct xfrm_kmaddress k;
	struct net *net = sock_net(sk);

	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1],
				     ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) ||
	    !ext_hdrs[SADB_X_EXT_POLICY - 1]) {
		err = -EINVAL;
		goto out;
	}

	kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1];
	pol = ext_hdrs[SADB_X_EXT_POLICY - 1];

	if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) {
		err = -EINVAL;
		goto out;
	}

	if (kma) {
		/* convert sadb_x_kmaddress to xfrm_kmaddress */
		k.reserved = kma->sadb_x_kmaddress_reserved;
		ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1),
					  8*(kma->sadb_x_kmaddress_len) - sizeof(*kma),
					  &k.local, &k.remote, &k.family);
		if (ret < 0) {
			err = ret;
			goto out;
		}
	}

	dir = pol->sadb_x_policy_dir - 1;
	memset(&sel, 0, sizeof(sel));

	/* set source address info of selector */
	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1];
	sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
	sel.prefixlen_s = sa->sadb_address_prefixlen;
	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
	sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port;
	if (sel.sport)
		sel.sport_mask = htons(0xffff);

	/* set destination address info of selector */
	sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1];
	pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
	sel.prefixlen_d = sa->sadb_address_prefixlen;
	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
	sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port;
	if (sel.dport)
		sel.dport_mask = htons(0xffff);

	rq = (struct sadb_x_ipsecrequest *)(pol + 1);

	/* extract ipsecrequests */
	i = 0;
	len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy);

	while (len > 0 && i < XFRM_MAX_DEPTH) {
		ret = ipsecrequests_to_migrate(rq, len, &m[i]);
		if (ret < 0) {
			err = ret;
			goto out;
		} else {
			rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret);
			len -= ret;
			i++;
		}
	}

	if (!i || len > 0) {
		err = -EINVAL;
		goto out;
	}

	return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
			    kma ? &k : NULL, net);

 out:
	return err;
}


MenuCacheDir* menu_cache_item_dup_parent( MenuCacheItem* item )
{
    MenuCacheDir* dir;
    MENU_CACHE_LOCK;
    dir = item->parent;
    if(G_LIKELY(dir))
        menu_cache_item_ref(MENU_CACHE_ITEM(dir));
    MENU_CACHE_UNLOCK;
    return dir;
}


static void read_app(GDataInputStream* f, MenuCacheApp* app, MenuCache* cache)
{
    char *line;
    gsize len;
    GString *str;

    /* generic name */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if(G_UNLIKELY(line == NULL))
        return;
    if(G_LIKELY(len > 0))
        app->generic_name = _unescape_lf(line);
    else
        g_free(line);

    /* exec */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if(G_UNLIKELY(line == NULL))
        return;
    if(G_LIKELY(len > 0))
        app->exec = _unescape_lf(line);
    else
        g_free(line);

    /* terminal / startup notify */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if(G_UNLIKELY(line == NULL))
        return;
    app->flags = (guint32)atoi(line);
    g_free(line);

    /* ShowIn flags */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if(G_UNLIKELY(line == NULL))
        return;
    app->show_in_flags = (guint32)atol(line);
    g_free(line);

    if (cache->version < 2)
        return;

    /* TryExec */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if (G_UNLIKELY(line == NULL))
        return;
    if (G_LIKELY(len > 0))
        app->try_exec = g_strchomp(line);
    else
        g_free(line);

    /* Path */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if (G_UNLIKELY(line == NULL))
        return;
    if (G_LIKELY(len > 0))
        app->working_dir = line;
    else
        g_free(line);

    /* Categories */
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if (G_UNLIKELY(line == NULL))
        return;
    if (G_LIKELY(len > 0))
    {
        const char **x;

        /* split and intern all the strings so categories can be processed
           later for search doing g_quark_try_string()+g_quark_to_string() */
        app->categories = x = (const char **)g_strsplit(line, ";", 0);
        while (*x != NULL)
        {
            char *cat = (char *)*x;
            *x = g_intern_string(cat);
            g_free(cat);
            x++;
        }
    }
    g_free(line);

    /* Keywords */
    str = g_string_new(MENU_CACHE_ITEM(app)->name);
    if (G_LIKELY(app->exec != NULL))
    {
        char *sp = strchr(app->exec, ' ');
        char *bn = strrchr(app->exec, G_DIR_SEPARATOR);

        g_string_append_c(str, ',');
        if (bn == NULL && sp == NULL)
            g_string_append(str, app->exec);
        else if (bn == NULL || (sp != NULL && sp < bn))
            g_string_append_len(str, app->exec, sp - app->exec);
        else if (sp == NULL)
            g_string_append(str, &bn[1]);
        else
            g_string_append_len(str, &bn[1], sp - &bn[1]);
    }
    if (app->generic_name != NULL)
    {
        g_string_append_c(str, ',');
        g_string_append(str, app->generic_name);
    }
    line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
    if (G_UNLIKELY(line == NULL))
        return;
    if (len > 0)
    {
        g_string_append_c(str, ',');
        g_string_append(str, line);
    }
    app->keywords = g_utf8_casefold(str->str, str->len);
    g_string_free(str, TRUE);
    g_free(line);
}


static void cache_free(Cache* cache)
{
    /* shutdown cache in 10 minutes of inactivity */
    if(!cache->delayed_free_handler)
        cache->delayed_free_handler = g_timeout_add_seconds(600,
                                                            delayed_cache_free,
                                                            cache);
    DEBUG("menu %p cache unused, removing in 600s", cache);
}


static void menu_cache_file_dir_unref(MenuCacheFileDir *file_dir)
{
    if (file_dir && g_atomic_int_dec_and_test(&file_dir->n_ref))
    {
        g_free(file_dir->dir);
        g_free(file_dir);
    }
}


static void read_dir(GDataInputStream* f, MenuCacheDir* dir, MenuCache* cache,
                     MenuCacheFileDir** all_used_files, int n_all_used_files)
{
    MenuCacheItem* item;
    char *line;
    gsize len;

    /* nodisplay flag */
    if (cache->version >= 2)
    {
        line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL);
        if (G_UNLIKELY(line == NULL))
            return;
        dir->flags = (guint32)atoi(line);
        g_free(line);
    }

    /* load child items in the dir */
    while( (item = read_item( f, cache, all_used_files, n_all_used_files )) )
    {
        /* menu_cache_ref shouldn't be called here for dir.
         * Otherwise, circular reference will happen. */
        item->parent = dir;
        dir->children = g_slist_prepend( dir->children, item );
    }

    dir->children = g_slist_reverse( dir->children );

    /* set flag by children if working with old cache generator */
    if (cache->version == 1)
    {
        if (dir->children == NULL)
            dir->flags = FLAG_IS_NODISPLAY;
        else if ((line = menu_cache_item_get_file_path(MENU_CACHE_ITEM(dir))) != NULL)
        {
            GKeyFile *kf = g_key_file_new();
            if (g_key_file_load_from_file(kf, line, G_KEY_FILE_NONE, NULL) &&
                g_key_file_get_boolean(kf, G_KEY_FILE_DESKTOP_GROUP,
                                       G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
                dir->flags = FLAG_IS_NODISPLAY;
            g_key_file_free(kf);
            g_free(line);
        }
    }
}


MenuCacheType menu_cache_item_get_type( MenuCacheItem* item )
{
    return item->type;
}


static gpointer server_io_thread(gpointer data)
{
    char buf[1024]; /* protocol has a lot shorter strings */
    ssize_t sz;
    size_t ptr = 0;
    int fd = GPOINTER_TO_INT(data);
    GHashTableIter it;
    char* menu_name;
    MenuCache* cache;

    while(fd >= 0)
    {
        sz = read(fd, &buf[ptr], sizeof(buf) - ptr);
        if(sz <= 0) /* socket error or EOF */
        {
            MENU_CACHE_LOCK;
            ptr = hash ? g_hash_table_size(hash) : 0;
            MENU_CACHE_UNLOCK;
            if (ptr == 0) /* don't need it anymore */
                break;
            G_LOCK(connect);
            if(fd != server_fd) /* someone replaced us?! go out immediately! */
            {
                G_UNLOCK(connect);
                break;
            }
            server_fd = -1;
            G_UNLOCK(connect);
            DEBUG("connect failed, trying reconnect");
            sleep(1);
            if( ! connect_server(NULL) )
            {
                g_critical("fail to re-connect to the server.");
                MENU_CACHE_LOCK;
                if(hash)
                {
                    g_hash_table_iter_init(&it, hash);
                    while(g_hash_table_iter_next(&it, (gpointer*)&menu_name, (gpointer*)&cache))
                        SET_CACHE_READY(cache);
                }
                MENU_CACHE_UNLOCK;
                break;
            }
            DEBUG("successfully reconnected server, re-register menus.");
            /* re-register all menu caches */
            MENU_CACHE_LOCK;
            if(hash)
            {
                g_hash_table_iter_init(&it, hash);
                while(g_hash_table_iter_next(&it, (gpointer*)&menu_name, (gpointer*)&cache))
                    register_menu_to_server(cache);
                    /* FIXME: need we remove it from hash if failed? */
            }
            MENU_CACHE_UNLOCK;
            break; /* next thread will do it */
        }
        while(sz > 0)
        {
            while(sz > 0)
            {
                if(buf[ptr] == '\n')
                    break;
                sz--;
                ptr++;
            }
            if(ptr == sizeof(buf)) /* EOB reached, seems we got garbage */
            {
                g_warning("menu cache: got garbage from server, break connect");
                shutdown(fd, SHUT_RDWR); /* drop connection */
                break; /* we handle it above */
            }
            else if(sz == 0) /* incomplete line, wait for data again */
                break;
            /* we got a line, let check what we got */
            buf[ptr] = '\0';
            if(memcmp(buf, "REL:", 4) == 0) /* reload */
            {
                DEBUG("server ask us to reload cache: %s", &buf[4]);
                MENU_CACHE_LOCK;
                if(hash)
                {
                    g_hash_table_iter_init(&it, hash);
                    while(g_hash_table_iter_next(&it, (gpointer*)&menu_name, (gpointer*)&cache))
                    {
                        if(memcmp(cache->md5, &buf[4], 32) == 0)
                        {
                            DEBUG("RELOAD!");
                            menu_cache_reload(cache);
                            SET_CACHE_READY(cache);
                            break;
                        }
                    }
                }
                MENU_CACHE_UNLOCK;
                /* DEBUG("cache reloaded"); */
            }
            else
                g_warning("menu cache: unrecognized input: %s", buf);
            /* go to next line */
            sz--;
            if(sz > 0)
                memmove(buf, &buf[ptr+1], sz);
            ptr = 0;
        }
    }
    G_LOCK(connect);
    if (fd == server_fd)
        server_fd = -1;
    G_UNLOCK(connect);
    close(fd);
    /* DEBUG("server io thread terminated"); */
#if GLIB_CHECK_VERSION(2, 32, 0)
    g_thread_unref(g_thread_self());
#endif
    return NULL;
}


static gboolean on_server_conn_close(GIOChannel* ch, GIOCondition cond, gpointer user_data)
{
    /* FIXME: is this possible? */
    /* the server socket is accidentally closed. terminate the server. */
    terminate(SIGTERM);
    return TRUE;
}


static void pre_exec( gpointer user_data )
{
    char** env = (char**)user_data;
    set_env(*env, "XDG_CACHE_HOME");
    set_env(*++env, "XDG_CONFIG_DIRS");
    set_env(*++env, "XDG_MENU_PREFIX");
    set_env(*++env, "XDG_DATA_DIRS");
    set_env(*++env, "XDG_CONFIG_HOME");
    set_env(*++env, "XDG_DATA_HOME");
    set_env(*++env, "CACHE_GEN_VERSION");
}


static void set_env( char* penv, const char* name )
{
    if( penv && *penv )
        g_setenv( name, penv, TRUE);
    else
        g_unsetenv( name );
}


MenuCacheNotifyId menu_cache_add_reload_notify(MenuCache* cache, MenuCacheReloadNotify func, gpointer user_data)
{
    GSList* l = g_slist_alloc();
    CacheReloadNotifier* n = g_slice_new(CacheReloadNotifier);
    gboolean is_first;
    n->func = func;
    n->user_data = user_data;
    l->data = n;
    MENU_CACHE_LOCK;
    is_first = (cache->root_dir == NULL && cache->notifiers == NULL);
    cache->notifiers = g_slist_concat( cache->notifiers, l );
    /* reload existing file first so it will be ready right away */
    if(is_first && cache->reload_id == 0)
        cache->reload_id = g_idle_add_full(G_PRIORITY_HIGH_IDLE,
                                           menu_cache_reload_idle,
                                           menu_cache_ref(cache),
                                           (GDestroyNotify)menu_cache_unref);
    MENU_CACHE_UNLOCK;
    return (MenuCacheNotifyId)l;
}


MenuCache* menu_cache_lookup( const char* menu_name )
{
    MenuCache* cache;

    /* lookup in a hash table for already loaded menus */
    MENU_CACHE_LOCK;
#if !GLIB_CHECK_VERSION(2, 32, 0)
    /* FIXME: destroy them on application exit? */
    if(!sync_run_mutex)
        sync_run_mutex = g_mutex_new();
    if(!sync_run_cond)
        sync_run_cond = g_cond_new();
#endif
    if( G_UNLIKELY( ! hash ) )
        hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL );
    else
    {
        cache = (MenuCache*)g_hash_table_lookup(hash, menu_name);
        if( cache )
        {
            menu_cache_ref(cache);
            MENU_CACHE_UNLOCK;
            return cache;
        }
    }
    MENU_CACHE_UNLOCK;

    cache = menu_cache_create(menu_name);
    cache->cancellable = g_cancellable_new();
#if GLIB_CHECK_VERSION(2, 32, 0)
    cache->thr = g_thread_new(menu_name, menu_cache_loader_thread, cache);
#else
    cache->thr = g_thread_create(menu_cache_loader_thread, cache, TRUE, NULL);
#endif
    return cache;
}


static gboolean menu_cache_reload_idle(gpointer cache)
{
    /* do reload once */
    if (!g_source_is_destroyed(g_main_current_source()))
        menu_cache_reload(cache);
    return FALSE;
}


static MenuCache* menu_cache_create(const char* menu_name)
{
    MenuCache* cache;
    const gchar * const * langs = g_get_language_names();
    const char* xdg_cfg_env = g_getenv("XDG_CONFIG_DIRS");
    const char* xdg_prefix_env = g_getenv("XDG_MENU_PREFIX");
    const char* xdg_data_env = g_getenv("XDG_DATA_DIRS");
    const char* xdg_cfg_home_env = g_getenv("XDG_CONFIG_HOME");
    const char* xdg_data_home_env = g_getenv("XDG_DATA_HOME");
    const char* xdg_cache_home_env = g_getenv("XDG_CACHE_HOME");
    char *xdg_cfg, *xdg_prefix, *xdg_data, *xdg_cfg_home, *xdg_data_home, *xdg_cache_home;
    char* buf;
    const char* md5;
    char* file_name;
    int len = 0;
    GChecksum *sum;
    char *langs_list;

    xdg_cfg = _validate_env(xdg_cfg_env);
    xdg_prefix = _validate_env(xdg_prefix_env);
    xdg_data = _validate_env(xdg_data_env);
    xdg_cfg_home = _validate_env(xdg_cfg_home_env);
    xdg_data_home = _validate_env(xdg_data_home_env);
    xdg_cache_home = _validate_env(xdg_cache_home_env);

    /* reconstruct languages list in form as it should be in $LANGUAGES */
    langs_list = g_strjoinv(":", (char **)langs);
    for (buf = langs_list; *buf; buf++) /* reusing buf var as char pointer */
        if (*buf == '\n' || *buf == '\t')
            *buf = ' ';

    buf = g_strdup_printf( "REG:%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t" CACHE_VERSION
                           "\t00000000000000000000000000000000\n",
                            menu_name,
                            langs_list,
                            xdg_cache_home,
                            xdg_cfg,
                            xdg_prefix,
                            xdg_data,
                            xdg_cfg_home,
                            xdg_data_home );

    /* calculate the md5 sum of menu name + lang + all environment variables */
    sum = g_checksum_new(G_CHECKSUM_MD5);
    len = strlen(buf);
    g_checksum_update(sum, (guchar*)buf + 4, len - 38);
    md5 = g_checksum_get_string(sum);
    file_name = g_build_filename( g_get_user_cache_dir(), "menus", md5, NULL );
    DEBUG("cache file_name = %s", file_name);
    cache = menu_cache_new( file_name );
    cache->reg = buf;
    cache->md5 = buf + len - 33;
    memcpy( cache->md5, md5, 32 );
    cache->menu_name = g_strdup(menu_name);
    g_free( file_name );
    g_free(langs_list);
    g_free(xdg_cfg);
    g_free(xdg_prefix);
    g_free(xdg_data);
    g_free(xdg_cfg_home);
    g_free(xdg_data_home);
    g_free(xdg_cache_home);

    g_checksum_free(sum); /* md5 is also freed here */

    MENU_CACHE_LOCK;
    g_hash_table_insert( hash, g_strdup(menu_name), cache );
    MENU_CACHE_UNLOCK;

    return cache;
}


static int __init lp_init (void)
{
	int i, err = 0;

	if (parport_nr[0] == LP_PARPORT_OFF)
		return 0;

	for (i = 0; i < LP_NO; i++) {
		lp_table[i].dev = NULL;
		lp_table[i].flags = 0;
		lp_table[i].chars = LP_INIT_CHAR;
		lp_table[i].time = LP_INIT_TIME;
		lp_table[i].wait = LP_INIT_WAIT;
		lp_table[i].lp_buffer = NULL;
#ifdef LP_STATS
		lp_table[i].lastcall = 0;
		lp_table[i].runchars = 0;
		memset (&lp_table[i].stats, 0, sizeof (struct lp_stats));
#endif
		lp_table[i].last_error = 0;
		init_waitqueue_head (&lp_table[i].waitq);
		init_waitqueue_head (&lp_table[i].dataq);
		mutex_init(&lp_table[i].port_mutex);
		lp_table[i].timeout = 10 * HZ;
	}

	if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
		printk (KERN_ERR "lp: unable to get major %d\n", LP_MAJOR);
		return -EIO;
	}

	lp_class = class_create(THIS_MODULE, "printer");
	if (IS_ERR(lp_class)) {
		err = PTR_ERR(lp_class);
		goto out_reg;
	}

	if (parport_register_driver (&lp_driver)) {
		printk (KERN_ERR "lp: unable to register with parport\n");
		err = -EIO;
		goto out_class;
	}

	if (!lp_count) {
		printk (KERN_INFO "lp: driver loaded but no devices found\n");
#ifndef CONFIG_PARPORT_1284
		if (parport_nr[0] == LP_PARPORT_AUTO)
			printk (KERN_INFO "lp: (is IEEE 1284 support enabled?)\n");
#endif
	}

	return 0;

out_class:
	class_destroy(lp_class);
out_reg:
	unregister_chrdev(LP_MAJOR, "lp");
	return err;
}


static int lp_wait_ready(int minor, int nonblock)
{
	int error = 0;

	/* If we're not in compatibility mode, we're ready now! */
	if (lp_table[minor].current_mode != IEEE1284_MODE_COMPAT) {
	  return (0);
	}

	do {
		error = lp_check_status (minor);
		if (error && (nonblock || (LP_F(minor) & LP_ABORT)))
			break;
		if (signal_pending (current)) {
			error = -EINTR;
			break;
		}
	} while (error);
	return error;
}


static int __init lp_init_module (void)
{
	if (parport[0]) {
		/* The user gave some parameters.  Let's see what they were.  */
		if (!strncmp(parport[0], "auto", 4))
			parport_nr[0] = LP_PARPORT_AUTO;
		else {
			int n;
			for (n = 0; n < LP_NO && parport[n]; n++) {
				if (!strncmp(parport[n], "none", 4))
					parport_nr[n] = LP_PARPORT_NONE;
				else {
					char *ep;
					unsigned long r = simple_strtoul(parport[n], &ep, 0);
					if (ep != parport[n])
						parport_nr[n] = r;
					else {
						printk(KERN_ERR "lp: bad port specifier `%s'\n", parport[n]);
						return -ENODEV;
					}
				}
			}
		}
	}

	return lp_init();
}


static int __init lp_setup (char *str)
{
	static int parport_ptr;
	int x;

	if (get_option(&str, &x)) {
		if (x == 0) {
			/* disable driver on "lp=" or "lp=0" */
			parport_nr[0] = LP_PARPORT_OFF;
		} else {
			printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", x);
			return 0;
		}
	} else if (!strncmp(str, "parport", 7)) {
		int n = simple_strtoul(str+7, NULL, 10);
		if (parport_ptr < LP_NO)
			parport_nr[parport_ptr++] = n;
		else
			printk(KERN_INFO "lp: too many ports, %s ignored.\n",
			       str);
	} else if (!strcmp(str, "auto")) {
		parport_nr[0] = LP_PARPORT_AUTO;
	} else if (!strcmp(str, "none")) {
		if (parport_ptr < LP_NO)
			parport_nr[parport_ptr++] = LP_PARPORT_NONE;
		else
			printk(KERN_INFO "lp: too many ports, %s ignored.\n",
			       str);
	} else if (!strcmp(str, "reset")) {
		reset = 1;
	}
	return 1;
}


ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_JMP, (OP_JMP_ADDR(op, op->op1) > op), ZEND_JMP_FORWARD, JMP_ADDR, ANY)
{
	USE_OPLINE

	OPLINE = OP_JMP_ADDR(opline, opline->op1);
	ZEND_VM_CONTINUE();
}


ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMPVAR|CV, NUM)
{
	USE_OPLINE
	zend_free_op free_op2;
	zend_string **rope;
	zval *var, *ret;
	uint32_t i;
	size_t len = 0;
	char *target;

	rope = (zend_string**)EX_VAR(opline->op1.var);
	if (OP2_TYPE == IS_CONST) {
		var = GET_OP2_ZVAL_PTR(BP_VAR_R);
		rope[opline->extended_value] = Z_STR_P(var);
		if (UNEXPECTED(Z_REFCOUNTED_P(var))) {
			Z_ADDREF_P(var);
		}
	} else {
		var = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
		if (EXPECTED(Z_TYPE_P(var) == IS_STRING)) {
			if (OP2_TYPE == IS_CV) {
				rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
			} else {
				rope[opline->extended_value] = Z_STR_P(var);
			}
		} else {
			SAVE_OPLINE();
			if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var) == IS_UNDEF)) {
				ZVAL_UNDEFINED_OP2();
			}
			rope[opline->extended_value] = zval_get_string_func(var);
			FREE_OP2();
			if (UNEXPECTED(EG(exception))) {
				for (i = 0; i <= opline->extended_value; i++) {
					zend_string_release_ex(rope[i], 0);
				}
				ZVAL_UNDEF(EX_VAR(opline->result.var));
				HANDLE_EXCEPTION();
			}
		}
	}
	for (i = 0; i <= opline->extended_value; i++) {
		len += ZSTR_LEN(rope[i]);
	}
	ret = EX_VAR(opline->result.var);
	ZVAL_STR(ret, zend_string_alloc(len, 0));
	target = Z_STRVAL_P(ret);
	for (i = 0; i <= opline->extended_value; i++) {
		memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i]));
		target += ZSTR_LEN(rope[i]);
		zend_string_release_ex(rope[i], 0);
	}
	*target = '\0';

	ZEND_VM_NEXT_OPCODE();
}


static zend_always_inline zend_long ZEND_FASTCALL _zval_get_long_func_ex(zval *op, zend_bool silent) /* {{{ */
{
try_again:
	switch (Z_TYPE_P(op)) {
		case IS_UNDEF:
		case IS_NULL:
		case IS_FALSE:
			return 0;
		case IS_TRUE:
			return 1;
		case IS_RESOURCE:
			return Z_RES_HANDLE_P(op);
		case IS_LONG:
			return Z_LVAL_P(op);
		case IS_DOUBLE:
			return zend_dval_to_lval(Z_DVAL_P(op));
		case IS_STRING:
			{
				zend_uchar type;
				zend_long lval;
				double dval;
				if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, silent ? 1 : -1))) {
					if (!silent) {
						zend_error(E_WARNING, "A non-numeric value encountered");
					}
					return 0;
				} else if (EXPECTED(type == IS_LONG)) {
					return lval;
				} else {
					/* Previously we used strtol here, not is_numeric_string,
					 * and strtol gives you LONG_MAX/_MIN on overflow.
					 * We use use saturating conversion to emulate strtol()'s
					 * behaviour.
					 */
					 return zend_dval_to_lval_cap(dval);
				}
			}
		case IS_ARRAY:
			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
		case IS_OBJECT:
			{
				zval dst;
				convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
				if (Z_TYPE(dst) == IS_LONG) {
					return Z_LVAL(dst);
				} else {
					return 1;
				}
			}
		case IS_REFERENCE:
			op = Z_REFVAL_P(op);
			goto try_again;
		EMPTY_SWITCH_DEFAULT_CASE()
	}
	return 0;
}


ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
{
	USE_OPLINE
	zval *prop;

	SAVE_OPLINE();

	if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) {
		ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
		prop = &EG(uninitialized_zval);
	}

	if (type == BP_VAR_R || type == BP_VAR_IS) {
		ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop);
	} else {
		ZVAL_INDIRECT(EX_VAR(opline->result.var), prop);
	}
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, NUM, SPEC(QUICK_ARG))
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *varptr, *arg;
	uint32_t arg_num = opline->op2.num;

	if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
		if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
			ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR);
		}

		varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
		arg = ZEND_CALL_VAR(EX(call), opline->result.var);
		ZVAL_COPY_VALUE(arg, varptr);

		if (EXPECTED(Z_ISREF_P(varptr) ||
		    QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
			ZEND_VM_NEXT_OPCODE();
		}
	} else {
		if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
			ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR);
		}

		varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
		arg = ZEND_CALL_VAR(EX(call), opline->result.var);
		ZVAL_COPY_VALUE(arg, varptr);

		if (EXPECTED(Z_ISREF_P(varptr) ||
		    ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
			ZEND_VM_NEXT_OPCODE();
		}
	}

	SAVE_OPLINE();
	ZVAL_NEW_REF(arg, arg);
	zend_error(E_NOTICE, "Only variables should be passed by reference");
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HOT_OBJ_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMPVAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *container;
	zend_free_op free_op2;
	zval *offset;
	void **cache_slot = NULL;

	SAVE_OPLINE();
	container = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R);

	if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
		ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper);
	}

	offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);

	if (OP1_TYPE == IS_CONST ||
	    (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT))) {
	    do {
			if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(container)) {
				container = Z_REFVAL_P(container);
				if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
					break;
				}
			}
			if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
				ZVAL_UNDEFINED_OP1();
			}
			if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
				ZVAL_UNDEFINED_OP2();
			}
			zend_wrong_property_read(offset);
			ZVAL_NULL(EX_VAR(opline->result.var));
			ZEND_VM_C_GOTO(fetch_obj_r_finish);
		} while (0);
	}

	/* here we are sure we are dealing with an object */
	do {
		zend_object *zobj = Z_OBJ_P(container);
		zval *retval;

		if (OP2_TYPE == IS_CONST) {
			cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_REF /* FUNC_ARG fetch may contain it */);

			if (EXPECTED(zobj->ce == CACHED_PTR_EX(cache_slot))) {
				uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);

				if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
					retval = OBJ_PROP(zobj, prop_offset);
					if (EXPECTED(Z_TYPE_INFO_P(retval) != IS_UNDEF)) {
						if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) {
							ZEND_VM_C_GOTO(fetch_obj_r_copy);
						} else {
ZEND_VM_C_LABEL(fetch_obj_r_fast_copy):
							ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
							ZEND_VM_NEXT_OPCODE();
						}
					}
				} else if (EXPECTED(zobj->properties != NULL)) {
					if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
						uintptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);

						if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
							Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);

							if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
						        (EXPECTED(p->key == Z_STR_P(offset)) ||
						         (EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
						          EXPECTED(p->key != NULL) &&
						          EXPECTED(zend_string_equal_content(p->key, Z_STR_P(offset)))))) {
								retval = &p->val;
								if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) {
									ZEND_VM_C_GOTO(fetch_obj_r_copy);
								} else {
									ZEND_VM_C_GOTO(fetch_obj_r_fast_copy);
								}
							}
						}
						CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
					}
					retval = zend_hash_find_ex(zobj->properties, Z_STR_P(offset), 1);
					if (EXPECTED(retval)) {
						uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
						CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
						if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) {
							ZEND_VM_C_GOTO(fetch_obj_r_copy);
						} else {
							ZEND_VM_C_GOTO(fetch_obj_r_fast_copy);
						}
					}
				}
			}
		} else if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(offset) == IS_UNDEF)) {
			ZVAL_UNDEFINED_OP2();
		}

		retval = zobj->handlers->read_property(container, offset, BP_VAR_R, cache_slot, EX_VAR(opline->result.var));

		if (retval != EX_VAR(opline->result.var)) {
ZEND_VM_C_LABEL(fetch_obj_r_copy):
			ZVAL_COPY_DEREF(EX_VAR(opline->result.var), retval);
		} else if (UNEXPECTED(Z_ISREF_P(retval))) {
			zend_unwrap_reference(retval);
		}
	} while (0);

ZEND_VM_C_LABEL(fetch_obj_r_finish):
	FREE_OP2();
	FREE_OP1();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HOT_HANDLER(42, ZEND_JMP, JMP_ADDR, ANY)
{
	USE_OPLINE

	ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op1), 0);
}


ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
	USE_OPLINE
	zval *op1, *op2;
	int result;

	op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	result = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
	ZEND_VM_SMART_BRANCH(result, 0);
	ZVAL_BOOL(EX_VAR(opline->result.var), result);
	ZEND_VM_NEXT_OPCODE();
}


ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_ADD_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
	USE_OPLINE
	zval *op1, *op2, *result;

	op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	result = EX_VAR(opline->result.var);
	ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
	ZEND_VM_NEXT_OPCODE();
}


ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT)
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *container;
	zval *offset;

	SAVE_OPLINE();
	container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET);
	if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
		ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper);
	}
	offset = GET_OP2_ZVAL_PTR(BP_VAR_R);

	do {
		if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
			if (Z_ISREF_P(container)) {
				container = Z_REFVAL_P(container);
				if (Z_TYPE_P(container) != IS_OBJECT) {
					if (OP1_TYPE == IS_CV
					 && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
						ZVAL_UNDEFINED_OP1();
					}
					break;
				}
			} else {
				break;
			}
		}
		Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL));
	} while (0);

	FREE_OP2();
	FREE_OP1_VAR_PTR();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
	USE_OPLINE
	zval *op1, *op2, *result;

	op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	result = EX_VAR(opline->result.var);
	ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
	ZEND_VM_NEXT_OPCODE();
}


ZEND_VM_COLD_CONSTCONST_HANDLER(15, ZEND_BOOL_XOR, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(COMMUTATIVE))
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *op1, *op2;

	SAVE_OPLINE();
	op1 = GET_OP1_ZVAL_PTR(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR(BP_VAR_R);
	boolean_xor_function(EX_VAR(opline->result.var), op1, op2);
	FREE_OP1();
	FREE_OP2();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *varptr, *arg;

	varptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
	arg = ZEND_CALL_VAR(EX(call), opline->result.var);
	ZVAL_COPY_VALUE(arg, varptr);

	if (EXPECTED(Z_ISREF_P(varptr))) {
		ZEND_VM_NEXT_OPCODE();
	}

	SAVE_OPLINE();
	ZVAL_NEW_REF(arg, arg);
	zend_error(E_NOTICE, "Only variables should be passed by reference");
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
	if (compare_function(result, op1, op2) == FAILURE) {
		return FAILURE;
	}
	ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
	return SUCCESS;
}


ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
	ZVAL_BOOL(result, zend_is_identical(op1, op2));
	return SUCCESS;
}


ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH_REF|DIM_OBJ_WRITE|CACHE_SLOT)
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *property, *container, *result;

	SAVE_OPLINE();

	container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
	if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
		ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper);
	}

	property = GET_OP2_ZVAL_PTR(BP_VAR_R);
	result = EX_VAR(opline->result.var);
	zend_fetch_property_address(
		result, container, OP1_TYPE, property, OP2_TYPE,
		((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL),
		BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC);
	FREE_OP2();
	if (OP1_TYPE == IS_VAR) {
		FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op1, result);
	}
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_COLD_CONSTCONST_HANDLER(19, ZEND_IS_NOT_EQUAL, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(SMART_BRANCH,COMMUTATIVE))
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *op1, *op2;
	double d1, d2;

	op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	if (ZEND_VM_SPEC && OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) {
		/* pass */
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
			if (EXPECTED(Z_LVAL_P(op1) != Z_LVAL_P(op2))) {
ZEND_VM_C_LABEL(is_not_equal_true):
				ZEND_VM_SMART_BRANCH_TRUE();
				ZVAL_TRUE(EX_VAR(opline->result.var));
				ZEND_VM_NEXT_OPCODE();
			} else {
ZEND_VM_C_LABEL(is_not_equal_false):
				ZEND_VM_SMART_BRANCH_FALSE();
				ZVAL_FALSE(EX_VAR(opline->result.var));
				ZEND_VM_NEXT_OPCODE();
			}
		} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
			d1 = (double)Z_LVAL_P(op1);
			d2 = Z_DVAL_P(op2);
			ZEND_VM_C_GOTO(is_not_equal_double);
		}
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
			d1 = Z_DVAL_P(op1);
			d2 = Z_DVAL_P(op2);
ZEND_VM_C_LABEL(is_not_equal_double):
			if (d1 != d2) {
				ZEND_VM_C_GOTO(is_not_equal_true);
			} else {
				ZEND_VM_C_GOTO(is_not_equal_false);
			}
		} else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
			d1 = Z_DVAL_P(op1);
			d2 = (double)Z_LVAL_P(op2);
			ZEND_VM_C_GOTO(is_not_equal_double);
		}
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
			int result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
			if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
				zval_ptr_dtor_str(op1);
			}
			if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) {
				zval_ptr_dtor_str(op2);
			}
			if (!result) {
				ZEND_VM_C_GOTO(is_not_equal_true);
			} else {
				ZEND_VM_C_GOTO(is_not_equal_false);
			}
		}
	}
	ZEND_VM_DISPATCH_TO_HELPER(zend_is_not_equal_helper, op_1, op1, op_2, op2);
}


ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, REF)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *expr_ptr, new_expr;

	SAVE_OPLINE();
	if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) &&
	    UNEXPECTED(opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
		expr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
		if (Z_ISREF_P(expr_ptr)) {
			Z_ADDREF_P(expr_ptr);
		} else {
			ZVAL_MAKE_REF_EX(expr_ptr, 2);
		}
		FREE_OP1_VAR_PTR();
	} else {
		expr_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
		if (OP1_TYPE == IS_TMP_VAR) {
			/* pass */
		} else if (OP1_TYPE == IS_CONST) {
			Z_TRY_ADDREF_P(expr_ptr);
		} else if (OP1_TYPE == IS_CV) {
			ZVAL_DEREF(expr_ptr);
			Z_TRY_ADDREF_P(expr_ptr);
		} else /* if (OP1_TYPE == IS_VAR) */ {
			if (UNEXPECTED(Z_ISREF_P(expr_ptr))) {
				zend_refcounted *ref = Z_COUNTED_P(expr_ptr);

				expr_ptr = Z_REFVAL_P(expr_ptr);
				if (UNEXPECTED(GC_DELREF(ref) == 0)) {
					ZVAL_COPY_VALUE(&new_expr, expr_ptr);
					expr_ptr = &new_expr;
					efree_size(ref, sizeof(zend_reference));
				} else if (Z_OPT_REFCOUNTED_P(expr_ptr)) {
					Z_ADDREF_P(expr_ptr);
				}
			}
		}
	}

	if (OP2_TYPE != IS_UNUSED) {
		zend_free_op free_op2;
		zval *offset = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
		zend_string *str;
		zend_ulong hval;

ZEND_VM_C_LABEL(add_again):
		if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
			str = Z_STR_P(offset);
			if (OP2_TYPE != IS_CONST) {
				if (ZEND_HANDLE_NUMERIC(str, hval)) {
					ZEND_VM_C_GOTO(num_index);
				}
			}
ZEND_VM_C_LABEL(str_index):
			zend_hash_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), str, expr_ptr);
		} else if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
			hval = Z_LVAL_P(offset);
ZEND_VM_C_LABEL(num_index):
			zend_hash_index_update(Z_ARRVAL_P(EX_VAR(opline->result.var)), hval, expr_ptr);
		} else if ((OP2_TYPE & (IS_VAR|IS_CV)) && EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
			offset = Z_REFVAL_P(offset);
			ZEND_VM_C_GOTO(add_again);
		} else if (Z_TYPE_P(offset) == IS_NULL) {
			str = ZSTR_EMPTY_ALLOC();
			ZEND_VM_C_GOTO(str_index);
		} else if (Z_TYPE_P(offset) == IS_DOUBLE) {
			hval = zend_dval_to_lval(Z_DVAL_P(offset));
			ZEND_VM_C_GOTO(num_index);
		} else if (Z_TYPE_P(offset) == IS_FALSE) {
			hval = 0;
			ZEND_VM_C_GOTO(num_index);
		} else if (Z_TYPE_P(offset) == IS_TRUE) {
			hval = 1;
			ZEND_VM_C_GOTO(num_index);
		} else if (Z_TYPE_P(offset) == IS_RESOURCE) {
			zend_use_resource_as_offset(offset);
			hval = Z_RES_HANDLE_P(offset);
			ZEND_VM_C_GOTO(num_index);
		} else if (OP2_TYPE == IS_CV && Z_TYPE_P(offset) == IS_UNDEF) {
			ZVAL_UNDEFINED_OP2();
			str = ZSTR_EMPTY_ALLOC();
			ZEND_VM_C_GOTO(str_index);
		} else {
			zend_illegal_offset();
			zval_ptr_dtor_nogc(expr_ptr);
		}
		FREE_OP2();
	} else {
		if (!zend_hash_next_index_insert(Z_ARRVAL_P(EX_VAR(opline->result.var)), expr_ptr)) {
			zend_cannot_add_element();
			zval_ptr_dtor_nogc(expr_ptr);
		}
	}
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_COLD_HANDLER(79, ZEND_EXIT, ANY, ANY)
{
	USE_OPLINE

	SAVE_OPLINE();
	if (OP1_TYPE != IS_UNUSED) {
		zend_free_op free_op1;
		zval *ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);

		do {
			if (Z_TYPE_P(ptr) == IS_LONG) {
				EG(exit_status) = Z_LVAL_P(ptr);
			} else {
				if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(ptr)) {
					ptr = Z_REFVAL_P(ptr);
					if (Z_TYPE_P(ptr) == IS_LONG) {
						EG(exit_status) = Z_LVAL_P(ptr);
						break;
					}
				}
				zend_print_zval(ptr, 0);
			}
		} while (0);
		FREE_OP1();
	}
	zend_bailout();
	ZEND_VM_NEXT_OPCODE(); /* Never reached */
}


ZEND_VM_HELPER(zend_pre_inc_helper, VAR|CV, ANY)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *var_ptr;

	var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);

	if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(var_ptr))) {
		if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
			ZVAL_NULL(EX_VAR(opline->result.var));
		}
		ZEND_VM_NEXT_OPCODE();
	}

	SAVE_OPLINE();
	if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) {
		ZVAL_NULL(var_ptr);
		ZVAL_UNDEFINED_OP1();
	}

	do {
		if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_REFERENCE)) {
			zend_reference *ref = Z_REF_P(var_ptr);
			var_ptr = Z_REFVAL_P(var_ptr);
			if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
				zend_incdec_typed_ref(ref, NULL OPLINE_CC EXECUTE_DATA_CC);
				break;
			}
		}
		increment_function(var_ptr);
	} while (0);

	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
		ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
	}

	FREE_OP1_VAR_PTR();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
{
	int retval;

	if (s1 == s2) {
		return 0;
	}
	retval = memcmp(s1, s2, MIN(len1, len2));
	if (!retval) {
		return (int)(len1 - len2);
	} else {
		return retval;
	}
}


ZEND_VM_HANDLER(48, ZEND_CASE, TMPVAR, CONST|TMPVAR|CV)
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *op1, *op2;
	double d1, d2;

	op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
			if (EXPECTED(Z_LVAL_P(op1) == Z_LVAL_P(op2))) {
ZEND_VM_C_LABEL(case_true):
				ZEND_VM_SMART_BRANCH_TRUE();
				ZVAL_TRUE(EX_VAR(opline->result.var));
				ZEND_VM_NEXT_OPCODE();
			} else {
ZEND_VM_C_LABEL(case_false):
				ZEND_VM_SMART_BRANCH_FALSE();
				ZVAL_FALSE(EX_VAR(opline->result.var));
				ZEND_VM_NEXT_OPCODE();
			}
		} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
			d1 = (double)Z_LVAL_P(op1);
			d2 = Z_DVAL_P(op2);
			ZEND_VM_C_GOTO(case_double);
		}
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
			d1 = Z_DVAL_P(op1);
			d2 = Z_DVAL_P(op2);
ZEND_VM_C_LABEL(case_double):
			if (d1 == d2) {
				ZEND_VM_C_GOTO(case_true);
			} else {
				ZEND_VM_C_GOTO(case_false);
			}
		} else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
			d1 = Z_DVAL_P(op1);
			d2 = (double)Z_LVAL_P(op2);
			ZEND_VM_C_GOTO(case_double);
		}
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
		if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
			int result = zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
			FREE_OP2();
			if (result) {
				ZEND_VM_C_GOTO(case_true);
			} else {
				ZEND_VM_C_GOTO(case_false);
			}
		}
	}
	ZEND_VM_DISPATCH_TO_HELPER(zend_case_helper, op_1, op1, op_2, op2);
}


ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
{
	USE_OPLINE
	zend_free_op free_op2;
	zval *function_name;
	zend_fcall_info_cache fcc;
	char *error = NULL;
	zend_function *func;
	void *object_or_called_scope;
	zend_execute_data *call;
	uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;

	SAVE_OPLINE();
	function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
	if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
		func = fcc.function_handler;
		if (error) {
			efree(error);
			/* This is the only soft error is_callable() can generate */
			zend_non_static_method_call(func);
			if (UNEXPECTED(EG(exception) != NULL)) {
				FREE_OP2();
				HANDLE_EXCEPTION();
			}
		}
		object_or_called_scope = fcc.called_scope;
		if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
			/* Delay closure destruction until its invocation */
			GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
			call_info |= ZEND_CALL_CLOSURE;
			if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
				call_info |= ZEND_CALL_FAKE_CLOSURE;
			}
			if (fcc.object) {
				object_or_called_scope = fcc.object;
				call_info |= ZEND_CALL_HAS_THIS;
			}
		} else if (fcc.object) {
			GC_ADDREF(fcc.object); /* For $this pointer */
			object_or_called_scope = fcc.object;
			call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
		}

		FREE_OP2();
		if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
			if (call_info & ZEND_CALL_CLOSURE) {
				zend_object_release(ZEND_CLOSURE_OBJECT(func));
			} else if (call_info & ZEND_CALL_RELEASE_THIS) {
				zend_object_release(fcc.object);
			}
			HANDLE_EXCEPTION();
		}

		if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) {
			init_func_run_time_cache(&func->op_array);
		}
	} else {
		zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), error);
		efree(error);
		FREE_OP2();
		if (UNEXPECTED(EG(exception))) {
			HANDLE_EXCEPTION();
		}
		func = (zend_function*)&zend_pass_function;
		object_or_called_scope = NULL;
	}

	call = zend_vm_stack_push_call_frame(call_info,
		func, opline->extended_value, object_or_called_scope);
	call->prev_execute_data = EX(call);
	EX(call) = call;

	ZEND_VM_NEXT_OPCODE();
}


ZEND_VM_COLD_CONSTCONST_HANDLER(187, ZEND_SWITCH_LONG, CONST|TMPVARCV, CONST, JMP_ADDR)
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *op, *jump_zv;
	HashTable *jumptable;

	op = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
	jumptable = Z_ARRVAL_P(GET_OP2_ZVAL_PTR(BP_VAR_R));

	if (Z_TYPE_P(op) != IS_LONG) {
		ZVAL_DEREF(op);
		if (Z_TYPE_P(op) != IS_LONG) {
			/* Wrong type, fall back to ZEND_CASE chain */
			ZEND_VM_NEXT_OPCODE();
		}
	}

	jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(op));
	if (jump_zv != NULL) {
		ZEND_VM_SET_RELATIVE_OPCODE(opline, Z_LVAL_P(jump_zv));
		ZEND_VM_CONTINUE();
	} else {
		/* default */
		ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
		ZEND_VM_CONTINUE();
	}
}


static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
{
	int carry=0;
	size_t pos=Z_STRLEN_P(str)-1;
	char *s;
	zend_string *t;
	int last=0; /* Shut up the compiler warning */
	int ch;

	if (Z_STRLEN_P(str) == 0) {
		zval_ptr_dtor_str(str);
		ZVAL_INTERNED_STR(str, ZSTR_CHAR('1'));
		return;
	}

	if (!Z_REFCOUNTED_P(str)) {
		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
		Z_TYPE_INFO_P(str) = IS_STRING_EX;
	} else if (Z_REFCOUNT_P(str) > 1) {
		Z_DELREF_P(str);
		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
	} else {
		zend_string_forget_hash_val(Z_STR_P(str));
	}
	s = Z_STRVAL_P(str);

	do {
		ch = s[pos];
		if (ch >= 'a' && ch <= 'z') {
			if (ch == 'z') {
				s[pos] = 'a';
				carry=1;
			} else {
				s[pos]++;
				carry=0;
			}
			last=LOWER_CASE;
		} else if (ch >= 'A' && ch <= 'Z') {
			if (ch == 'Z') {
				s[pos] = 'A';
				carry=1;
			} else {
				s[pos]++;
				carry=0;
			}
			last=UPPER_CASE;
		} else if (ch >= '0' && ch <= '9') {
			if (ch == '9') {
				s[pos] = '0';
				carry=1;
			} else {
				s[pos]++;
				carry=0;
			}
			last = NUMERIC;
		} else {
			carry=0;
			break;
		}
		if (carry == 0) {
			break;
		}
	} while (pos-- > 0);

	if (carry) {
		t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
		memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
		ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
		switch (last) {
			case NUMERIC:
				ZSTR_VAL(t)[0] = '1';
				break;
			case UPPER_CASE:
				ZSTR_VAL(t)[0] = 'A';
				break;
			case LOWER_CASE:
				ZSTR_VAL(t)[0] = 'a';
				break;
		}
		zend_string_free(Z_STR_P(str));
		ZVAL_NEW_STR(str, t);
	}
}


ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2)
{
	USE_OPLINE

	SAVE_OPLINE();
	if (UNEXPECTED(Z_TYPE_INFO_P(op_1) == IS_UNDEF)) {
		op_1 = ZVAL_UNDEFINED_OP1();
	}
	if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) {
		op_2 = ZVAL_UNDEFINED_OP2();
	}
	compare_function(EX_VAR(opline->result.var), op_1, op_2);
	if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) {
		zval_ptr_dtor_nogc(op_1);
	}
	if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) {
		zval_ptr_dtor_nogc(op_2);
	}
	if (UNEXPECTED(EG(exception))) {
		HANDLE_EXCEPTION();
	}
	if (Z_LVAL_P(EX_VAR(opline->result.var)) == 0) {
		ZEND_VM_SMART_BRANCH_TRUE();
		ZVAL_TRUE(EX_VAR(opline->result.var));
		ZEND_VM_NEXT_OPCODE();
	} else {
		ZEND_VM_SMART_BRANCH_FALSE();
		ZVAL_FALSE(EX_VAR(opline->result.var));
		ZEND_VM_NEXT_OPCODE();
	}
}


ZEND_VM_HANDLER(24, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_SLOT, SPEC(OP_DATA=CONST|TMP|VAR|CV))
{
	USE_OPLINE
	zend_free_op free_op1, free_op2, free_op_data;
	zval *object, *property, *value, tmp;

	SAVE_OPLINE();
	object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);

	if (OP1_TYPE == IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) == IS_UNDEF)) {
		ZEND_VM_DISPATCH_TO_HELPER(zend_this_not_in_object_context_helper);
	}

	property = GET_OP2_ZVAL_PTR(BP_VAR_R);
	value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R);

	if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
		if (Z_ISREF_P(object) && Z_TYPE_P(Z_REFVAL_P(object)) == IS_OBJECT) {
			object = Z_REFVAL_P(object);
			ZEND_VM_C_GOTO(assign_object);
		}
		object = make_real_object(object, property OPLINE_CC EXECUTE_DATA_CC);
		if (UNEXPECTED(!object)) {
			value = &EG(uninitialized_zval);
			ZEND_VM_C_GOTO(free_and_exit_assign_obj);
		}
	}

ZEND_VM_C_LABEL(assign_object):
	if (OP2_TYPE == IS_CONST &&
	    EXPECTED(Z_OBJCE_P(object) == CACHED_PTR(opline->extended_value))) {
		void **cache_slot = CACHE_ADDR(opline->extended_value);
		uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
		zend_object *zobj = Z_OBJ_P(object);
		zval *property_val;

		if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
			property_val = OBJ_PROP(zobj, prop_offset);
			if (Z_TYPE_P(property_val) != IS_UNDEF) {
				zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2);

				if (UNEXPECTED(prop_info != NULL)) {
					value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
					ZEND_VM_C_GOTO(free_and_exit_assign_obj);
				} else {
ZEND_VM_C_LABEL(fast_assign_obj):
					value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
					if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
						ZVAL_COPY(EX_VAR(opline->result.var), value);
					}
					ZEND_VM_C_GOTO(exit_assign_obj);
				}
			}
		} else {
			if (EXPECTED(zobj->properties != NULL)) {
				if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
					if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
						GC_DELREF(zobj->properties);
					}
					zobj->properties = zend_array_dup(zobj->properties);
				}
				property_val = zend_hash_find_ex(zobj->properties, Z_STR_P(property), 1);
				if (property_val) {
					ZEND_VM_C_GOTO(fast_assign_obj);
				}
			}

			if (!zobj->ce->__set) {

				if (EXPECTED(zobj->properties == NULL)) {
					rebuild_object_properties(zobj);
				}
				if (OP_DATA_TYPE == IS_CONST) {
					if (UNEXPECTED(Z_OPT_REFCOUNTED_P(value))) {
						Z_ADDREF_P(value);
					}
				} else if (OP_DATA_TYPE != IS_TMP_VAR) {
					if (Z_ISREF_P(value)) {
						if (OP_DATA_TYPE == IS_VAR) {
							zend_reference *ref = Z_REF_P(value);
							if (GC_DELREF(ref) == 0) {
								ZVAL_COPY_VALUE(&tmp, Z_REFVAL_P(value));
								efree_size(ref, sizeof(zend_reference));
								value = &tmp;
							} else {
								value = Z_REFVAL_P(value);
								Z_TRY_ADDREF_P(value);
							}
						} else {
							value = Z_REFVAL_P(value);
							Z_TRY_ADDREF_P(value);
						}
					} else if (OP_DATA_TYPE == IS_CV) {
						Z_TRY_ADDREF_P(value);
					}
				}
				zend_hash_add_new(zobj->properties, Z_STR_P(property), value);
				if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
					ZVAL_COPY(EX_VAR(opline->result.var), value);
				}
				ZEND_VM_C_GOTO(exit_assign_obj);
			}
		}
	}

	if (OP_DATA_TYPE == IS_CV || OP_DATA_TYPE == IS_VAR) {
		ZVAL_DEREF(value);
	}

	value = Z_OBJ_HT_P(object)->write_property(object, property, value, (OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL);

ZEND_VM_C_LABEL(free_and_exit_assign_obj):
	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
		ZVAL_COPY(EX_VAR(opline->result.var), value);
	}
	FREE_OP_DATA();
ZEND_VM_C_LABEL(exit_assign_obj):
	FREE_OP2();
	FREE_OP1_VAR_PTR();
	/* assign_obj has two opcodes! */
	ZEND_VM_NEXT_OPCODE_EX(1, 2);
}


ZEND_VM_COLD_CONST_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, JMP_ADDR)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *value;
	zval *ref = NULL;
	int ret;

	SAVE_OPLINE();
	value = GET_OP1_ZVAL_PTR(BP_VAR_R);

	if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) && Z_ISREF_P(value)) {
		if (OP1_TYPE == IS_VAR) {
			ref = value;
		}
		value = Z_REFVAL_P(value);
	}

	ret = i_zend_is_true(value);

	if (UNEXPECTED(EG(exception))) {
		FREE_OP1();
		ZVAL_UNDEF(EX_VAR(opline->result.var));
		HANDLE_EXCEPTION();
	}

	if (ret) {
		zval *result = EX_VAR(opline->result.var);

		ZVAL_COPY_VALUE(result, value);
		if (OP1_TYPE == IS_CONST) {
			if (UNEXPECTED(Z_OPT_REFCOUNTED_P(result))) Z_ADDREF_P(result);
		} else if (OP1_TYPE == IS_CV) {
			if (Z_OPT_REFCOUNTED_P(result)) Z_ADDREF_P(result);
		} else if (OP1_TYPE == IS_VAR && ref) {
			zend_reference *r = Z_REF_P(ref);

			if (UNEXPECTED(GC_DELREF(r) == 0)) {
				efree_size(r, sizeof(zend_reference));
			} else if (Z_OPT_REFCOUNTED_P(result)) {
				Z_ADDREF_P(result);
			}
		}
		ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0);
	}

	FREE_OP1();
	ZEND_VM_NEXT_OPCODE();
}


ZEND_VM_COLD_CONST_HANDLER(193, ZEND_GET_TYPE, CONST|TMP|VAR|CV, UNUSED)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *op1;
	zend_string *type;

	SAVE_OPLINE();
	op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
	type = zend_zval_get_type(op1);
	if (EXPECTED(type)) {
		ZVAL_INTERNED_STR(EX_VAR(opline->result.var), type);
	} else {
		ZVAL_STRING(EX_VAR(opline->result.var), "unknown type");
	}
	FREE_OP1();
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HANDLER(86, ZEND_FETCH_RW, CONST|TMPVAR|CV, UNUSED, VAR_FETCH)
{
	ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_RW);
}


ZEND_VM_COLD_CONST_HANDLER(46, ZEND_JMPZ_EX, CONST|TMPVAR|CV, JMP_ADDR)
{
	USE_OPLINE
	zend_free_op free_op1;
	zval *val;
	int ret;

	val = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);

	if (Z_TYPE_INFO_P(val) == IS_TRUE) {
		ZVAL_TRUE(EX_VAR(opline->result.var));
		ZEND_VM_NEXT_OPCODE();
	} else if (EXPECTED(Z_TYPE_INFO_P(val) <= IS_TRUE)) {
		ZVAL_FALSE(EX_VAR(opline->result.var));
		if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(val) == IS_UNDEF)) {
			SAVE_OPLINE();
			ZVAL_UNDEFINED_OP1();
			if (UNEXPECTED(EG(exception))) {
				HANDLE_EXCEPTION();
			}
		}
		ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0);
	}

	SAVE_OPLINE();
	ret = i_zend_is_true(val);
	FREE_OP1();
	if (ret) {
		ZVAL_TRUE(EX_VAR(opline->result.var));
		opline++;
	} else {
		ZVAL_FALSE(EX_VAR(opline->result.var));
		opline = OP_JMP_ADDR(opline, opline->op2);
	}
	ZEND_VM_JMP(opline);
}


ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
{
	if (Z_TYPE_P(op1) < IS_TRUE) {
		ZVAL_TRUE(result);
	} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
		ZVAL_FALSE(result);
	} else {
		if (Z_ISREF_P(op1)) {
			op1 = Z_REFVAL_P(op1);
			if (Z_TYPE_P(op1) < IS_TRUE) {
				ZVAL_TRUE(result);
				return SUCCESS;
			} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
				ZVAL_FALSE(result);
				return SUCCESS;
			}
		}
		ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);

		ZVAL_BOOL(result, !zval_is_true(op1));
	}
	return SUCCESS;
}


ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FE_FETCH_R, op->op2_type == IS_CV && (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY, ZEND_FE_FETCH_R_SIMPLE, VAR, CV, JMP_ADDR, SPEC(RETVAL))
{
	USE_OPLINE
	zval *array;
	zval *value, *variable_ptr;
	uint32_t value_type;
	HashTable *fe_ht;
	HashPosition pos;
	Bucket *p;

	array = EX_VAR(opline->op1.var);
	SAVE_OPLINE();
	fe_ht = Z_ARRVAL_P(array);
	pos = Z_FE_POS_P(array);
	p = fe_ht->arData + pos;
	while (1) {
		if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
			/* reached end of iteration */
			ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
			ZEND_VM_CONTINUE();
		}
		value = &p->val;
		value_type = Z_TYPE_INFO_P(value);
		if (EXPECTED(value_type != IS_UNDEF)) {
			if (UNEXPECTED(value_type == IS_INDIRECT)) {
				value = Z_INDIRECT_P(value);
				value_type = Z_TYPE_INFO_P(value);
				if (EXPECTED(value_type != IS_UNDEF)) {
					break;
				}
			} else {
				break;
			}
		}
		pos++;
		p++;
	}
	Z_FE_POS_P(array) = pos + 1;
	if (RETURN_VALUE_USED(opline)) {
		if (!p->key) {
			ZVAL_LONG(EX_VAR(opline->result.var), p->h);
		} else {
			ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
		}
	}

	variable_ptr = EX_VAR(opline->op2.var);
	zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}


ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC)
{
	USE_OPLINE
	zend_free_op free_op_data;
	zval *prop, *value_ptr;
	zend_property_info *prop_info;

	SAVE_OPLINE();

	if (zend_fetch_static_property_address(&prop, &prop_info, opline->extended_value & ~ZEND_RETURNS_FUNCTION, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
		FREE_UNFETCHED_OP_DATA();
		UNDEF_RESULT();
		HANDLE_EXCEPTION();
	}

	value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W);

	if (OP_DATA_TYPE == IS_VAR && UNEXPECTED(Z_ISERROR_P(value_ptr))) {
		prop = &EG(uninitialized_zval);
	} else if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) {
		if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) {
			prop = &EG(uninitialized_zval);
		}
	} else if (UNEXPECTED(prop_info->type)) {
		prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC);
	} else {
		zend_assign_to_variable_reference(prop, value_ptr);
	}

	if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
		ZVAL_COPY(EX_VAR(opline->result.var), prop);
	}

	FREE_OP_DATA_VAR_PTR();
	ZEND_VM_NEXT_OPCODE_EX(1, 2);
}


xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
    if ((buf == NULL) || (table == NULL))
        return;
    xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
}


xmlWalkValidateList(const void *data, const void *user)
{
	xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
	xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
	return 1;
}


xmlErrValidWarning(xmlValidCtxtPtr ctxt,
                xmlNodePtr node, xmlParserErrors error,
                const char *msg, const xmlChar * str1,
                const xmlChar * str2, const xmlChar * str3)
{
    xmlStructuredErrorFunc schannel = NULL;
    xmlGenericErrorFunc channel = NULL;
    xmlParserCtxtPtr pctxt = NULL;
    void *data = NULL;

    if (ctxt != NULL) {
        channel = ctxt->warning;
        data = ctxt->userData;
	/* Use the special values to detect if it is part of a parsing
	   context */
	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
	    long delta = (char *) ctxt - (char *) ctxt->userData;
	    if ((delta > 0) && (delta < 250))
		pctxt = ctxt->userData;
	}
    }
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
                    XML_ERR_WARNING, NULL, 0,
                    (const char *) str1,
                    (const char *) str1,
                    (const char *) str3, 0, 0, msg, str1, str2, str3);
}


xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
    xmlDumpNotationDecl(buf, nota);
}


xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
    if ((buf == NULL) || (table == NULL))
        return;
    xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
}


xmlCopyNotationTable(xmlNotationTablePtr table) {
    return((xmlNotationTablePtr) xmlHashCopy(table,
				    (xmlHashCopier) xmlCopyNotation));
}


static void virtio_unref_resource(pixman_image_t *image, void *data)
{
    pixman_image_unref(data);
}


e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
{
    static const uint32_t ims_ext_mask =
        E1000_IMS_RXQ0 | E1000_IMS_RXQ1 |
        E1000_IMS_TXQ0 | E1000_IMS_TXQ1 |
        E1000_IMS_OTHER;

    static const uint32_t ims_valid_mask =
        E1000_IMS_TXDW      | E1000_IMS_TXQE    | E1000_IMS_LSC  |
        E1000_IMS_RXDMT0    | E1000_IMS_RXO     | E1000_IMS_RXT0 |
        E1000_IMS_MDAC      | E1000_IMS_TXD_LOW | E1000_IMS_SRPD |
        E1000_IMS_ACK       | E1000_IMS_MNG     | E1000_IMS_RXQ0 |
        E1000_IMS_RXQ1      | E1000_IMS_TXQ0    | E1000_IMS_TXQ1 |
        E1000_IMS_OTHER;

    uint32_t valid_val = val & ims_valid_mask;

    trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
    core->mac[IMS] |= valid_val;

    if ((valid_val & ims_ext_mask) &&
        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
        msix_enabled(core->owner)) {
        e1000e_msix_clear(core, valid_val);
    }

    if ((valid_val == ims_valid_mask) &&
        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA)) {
        trace_e1000e_irq_fire_all_timers(val);
        e1000e_intrmgr_fire_all_timers(core);
    }

    e1000e_update_interrupt_state(core);
}


e1000e_verify_csum_in_sw(E1000ECore *core,
                         struct NetRxPkt *pkt,
                         uint32_t *status_flags,
                         bool istcp, bool isudp)
{
    bool csum_valid;
    uint32_t csum_error;

    if (e1000e_rx_l3_cso_enabled(core)) {
        if (!net_rx_pkt_validate_l3_csum(pkt, &csum_valid)) {
            trace_e1000e_rx_metadata_l3_csum_validation_failed();
        } else {
            csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_IPE;
            *status_flags |= E1000_RXD_STAT_IPCS | csum_error;
        }
    } else {
        trace_e1000e_rx_metadata_l3_cso_disabled();
    }

    if (!e1000e_rx_l4_cso_enabled(core)) {
        trace_e1000e_rx_metadata_l4_cso_disabled();
        return;
    }

    if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
        trace_e1000e_rx_metadata_l4_csum_validation_failed();
        return;
    }

    csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_TCPE;

    if (istcp) {
        *status_flags |= E1000_RXD_STAT_TCPCS |
                         csum_error;
    } else if (isudp) {
        *status_flags |= E1000_RXD_STAT_TCPCS |
                         E1000_RXD_STAT_UDPCS |
                         csum_error;
    }
}


static uint32_t
e1000e_get_tarc(E1000ECore *core, int index)
{
    return core->mac[index] & ((BIT(11) - 1) |
                                BIT(27)      |
                                BIT(28)      |
                                BIT(29)      |
                                BIT(30));


e1000e_build_rx_metadata(E1000ECore *core,
                         struct NetRxPkt *pkt,
                         bool is_eop,
                         const E1000E_RSSInfo *rss_info,
                         uint32_t *rss, uint32_t *mrq,
                         uint32_t *status_flags,
                         uint16_t *ip_id,
                         uint16_t *vlan_tag)
{
    struct virtio_net_hdr *vhdr;
    bool isip4, isip6, istcp, isudp;
    uint32_t pkt_type;

    *status_flags = E1000_RXD_STAT_DD;

    /* No additional metadata needed for non-EOP descriptors */
    if (!is_eop) {
        goto func_exit;
    }

    *status_flags |= E1000_RXD_STAT_EOP;

    net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
    trace_e1000e_rx_metadata_protocols(isip4, isip6, isudp, istcp);

    /* VLAN state */
    if (net_rx_pkt_is_vlan_stripped(pkt)) {
        *status_flags |= E1000_RXD_STAT_VP;
        *vlan_tag = cpu_to_le16(net_rx_pkt_get_vlan_tag(pkt));
        trace_e1000e_rx_metadata_vlan(*vlan_tag);
    }

    /* Packet parsing results */
    if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) {
        if (rss_info->enabled) {
            *rss = cpu_to_le32(rss_info->hash);
            *mrq = cpu_to_le32(rss_info->type | (rss_info->queue << 8));
            trace_e1000e_rx_metadata_rss(*rss, *mrq);
        }
    } else if (isip4) {
            *status_flags |= E1000_RXD_STAT_IPIDV;
            *ip_id = cpu_to_le16(net_rx_pkt_get_ip_id(pkt));
            trace_e1000e_rx_metadata_ip_id(*ip_id);
    }

    if (istcp && e1000e_is_tcp_ack(core, pkt)) {
        *status_flags |= E1000_RXD_STAT_ACK;
        trace_e1000e_rx_metadata_ack();
    }

    if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) {
        trace_e1000e_rx_metadata_ipv6_filtering_disabled();
        pkt_type = E1000_RXD_PKT_MAC;
    } else if (istcp || isudp) {
        pkt_type = isip4 ? E1000_RXD_PKT_IP4_XDP : E1000_RXD_PKT_IP6_XDP;
    } else if (isip4 || isip6) {
        pkt_type = isip4 ? E1000_RXD_PKT_IP4 : E1000_RXD_PKT_IP6;
    } else {
        pkt_type = E1000_RXD_PKT_MAC;
    }

    *status_flags |= E1000_RXD_PKT_TYPE(pkt_type);
    trace_e1000e_rx_metadata_pkt_type(pkt_type);

    /* RX CSO information */
    if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_XSUM_DIS)) {
        trace_e1000e_rx_metadata_ipv6_sum_disabled();
        goto func_exit;
    }

    if (!net_rx_pkt_has_virt_hdr(pkt)) {
        trace_e1000e_rx_metadata_no_virthdr();
        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
        goto func_exit;
    }

    vhdr = net_rx_pkt_get_vhdr(pkt);

    if (!(vhdr->flags & VIRTIO_NET_HDR_F_DATA_VALID) &&
        !(vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
        trace_e1000e_rx_metadata_virthdr_no_csum_info();
        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
        goto func_exit;
    }

    if (e1000e_rx_l3_cso_enabled(core)) {
        *status_flags |= isip4 ? E1000_RXD_STAT_IPCS : 0;
    } else {
        trace_e1000e_rx_metadata_l3_cso_disabled();
    }

    if (e1000e_rx_l4_cso_enabled(core)) {
        if (istcp) {
            *status_flags |= E1000_RXD_STAT_TCPCS;
        } else if (isudp) {
            *status_flags |= E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS;
        }
    } else {
        trace_e1000e_rx_metadata_l4_cso_disabled();
    }

    trace_e1000e_rx_metadata_status_flags(*status_flags);

func_exit:
    *status_flags = cpu_to_le32(*status_flags);
}


e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
{
    if (tx->props.tse && tx->props.cptse) {
        net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
        net_tx_pkt_update_ip_checksums(tx->tx_pkt);
        e1000x_inc_reg_if_not_full(core->mac, TSCTC);
        return;
    }

    if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) {
        net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0);
    }

    if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) {
        net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt);
    }
}


e1000e_msix_notify(E1000ECore *core, uint32_t causes)
{
    if (causes & E1000_ICR_RXQ0) {
        e1000e_msix_notify_one(core, E1000_ICR_RXQ0,
                               E1000_IVAR_RXQ0(core->mac[IVAR]));
    }

    if (causes & E1000_ICR_RXQ1) {
        e1000e_msix_notify_one(core, E1000_ICR_RXQ1,
                               E1000_IVAR_RXQ1(core->mac[IVAR]));
    }

    if (causes & E1000_ICR_TXQ0) {
        e1000e_msix_notify_one(core, E1000_ICR_TXQ0,
                               E1000_IVAR_TXQ0(core->mac[IVAR]));
    }

    if (causes & E1000_ICR_TXQ1) {
        e1000e_msix_notify_one(core, E1000_ICR_TXQ1,
                               E1000_IVAR_TXQ1(core->mac[IVAR]));
    }

    if (causes & E1000_ICR_OTHER) {
        e1000e_msix_notify_one(core, E1000_ICR_OTHER,
                               E1000_IVAR_OTHER(core->mac[IVAR]));
    }
}


e1000e_set_ctrlext(E1000ECore *core, int index, uint32_t val)
{
    trace_e1000e_link_set_ext_params(!!(val & E1000_CTRL_EXT_ASDCHK),
                                     !!(val & E1000_CTRL_EXT_SPD_BYPS));

    /* Zero self-clearing bits */
    val &= ~(E1000_CTRL_EXT_ASDCHK | E1000_CTRL_EXT_EE_RST);
    core->mac[CTRL_EXT] = val;
}


e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
{
    core->mac[r->dh] += count;

    if (core->mac[r->dh] * E1000_RING_DESC_LEN >= core->mac[r->dlen]) {
        core->mac[r->dh] = 0;
    }
}


e1000e_parse_rxbufsize(E1000ECore *core)
{
    uint32_t rctl = core->mac[RCTL];

    memset(core->rxbuf_sizes, 0, sizeof(core->rxbuf_sizes));

    if (rctl & E1000_RCTL_DTYP_MASK) {
        uint32_t bsize;

        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE0_MASK;
        core->rxbuf_sizes[0] = (bsize >> E1000_PSRCTL_BSIZE0_SHIFT) * 128;

        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE1_MASK;
        core->rxbuf_sizes[1] = (bsize >> E1000_PSRCTL_BSIZE1_SHIFT) * 1024;

        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE2_MASK;
        core->rxbuf_sizes[2] = (bsize >> E1000_PSRCTL_BSIZE2_SHIFT) * 1024;

        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE3_MASK;
        core->rxbuf_sizes[3] = (bsize >> E1000_PSRCTL_BSIZE3_SHIFT) * 1024;
    } else if (rctl & E1000_RCTL_FLXBUF_MASK) {
        int flxbuf = rctl & E1000_RCTL_FLXBUF_MASK;
        core->rxbuf_sizes[0] = (flxbuf >> E1000_RCTL_FLXBUF_SHIFT) * 1024;
    } else {
        core->rxbuf_sizes[0] = e1000x_rxbufsize(rctl);
    }

    trace_e1000e_rx_desc_buff_sizes(core->rxbuf_sizes[0], core->rxbuf_sizes[1],
                                    core->rxbuf_sizes[2], core->rxbuf_sizes[3]);

    e1000e_calc_per_desc_buf_size(core);
}


e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx)
{
    static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
        { TDBAH,  TDBAL,  TDLEN,  TDH,  TDT, 0 },
        { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 }
    };

    assert(idx < ARRAY_SIZE(i));

    txr->i     = &i[idx];
    txr->tx    = &core->tx[idx];
}


static uint32_t
e1000e_mac_icr_read(E1000ECore *core, int index)
{
    uint32_t ret = core->mac[ICR];
    trace_e1000e_irq_icr_read_entry(ret);

    if (core->mac[IMS] == 0) {
        trace_e1000e_irq_icr_clear_zero_ims();
        core->mac[ICR] = 0;
    }

    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
        trace_e1000e_irq_icr_clear_iame();
        core->mac[ICR] = 0;
        trace_e1000e_irq_icr_process_iame();
        e1000e_clear_ims_bits(core, core->mac[IAM]);
    }

    trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
    e1000e_update_interrupt_state(core);
    return ret;


e1000e_set_phy_page(E1000ECore *core, int index, uint16_t val)
{
    core->phy[0][PHY_PAGE] = val & PHY_PAGE_RW_MASK;
}


e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
{
    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
        trace_e1000e_irq_icr_process_iame();
        e1000e_clear_ims_bits(core, core->mac[IAM]);
    }

    trace_e1000e_irq_icr_write(val, core->mac[ICR], core->mac[ICR] & ~val);
    core->mac[ICR] &= ~val;
    e1000e_update_interrupt_state(core);
}


e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
{
    static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
                                    PTC1023, PTC1522 };

    size_t tot_len = net_tx_pkt_get_total_len(tx_pkt);

    e1000x_increase_size_stats(core->mac, PTCregs, tot_len);
    e1000x_inc_reg_if_not_full(core->mac, TPT);
    e1000x_grow_8reg_if_not_full(core->mac, TOTL, tot_len);

    switch (net_tx_pkt_get_packet_type(tx_pkt)) {
    case ETH_PKT_BCAST:
        e1000x_inc_reg_if_not_full(core->mac, BPTC);
        break;
    case ETH_PKT_MCAST:
        e1000x_inc_reg_if_not_full(core->mac, MPTC);
        break;
    case ETH_PKT_UCAST:
        break;
    default:
        g_assert_not_reached();
    }

    core->mac[GPTC] = core->mac[TPT];
    core->mac[GOTCL] = core->mac[TOTL];
    core->mac[GOTCH] = core->mac[TOTH];
}


static void
e1000e_set_rxcsum(E1000ECore *core, int index, uint32_t val)
{
    core->mac[RXCSUM] = val;
    e1000e_update_rx_offloads(core);


e1000e_rx_wb_interrupt_cause(E1000ECore *core, int queue_idx,
                             bool min_threshold_hit)
{
    if (!msix_enabled(core->owner)) {
        return E1000_ICS_RXT0 | (min_threshold_hit ? E1000_ICS_RXDMT0 : 0);
    }

    return (queue_idx == 0) ? E1000_ICR_RXQ0 : E1000_ICR_RXQ1;
}


e1000e_rx_use_legacy_descriptor(E1000ECore *core)
{
    return (core->mac[RFCTL] & E1000_RFCTL_EXTEN) ? false : true;
}