void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks)
{
        memset(gif, 0, sizeof(gif_animation));
        gif->bitmap_callbacks = *bitmap_callbacks;
        gif->decoded_frame = GIF_INVALID_FRAME;
}


static MOBI_RET mobi_parse_tagx(MOBIBuffer *buf, MOBITagx *tagx) {
    tagx->control_byte_count = 0;
    tagx->tags_count = 0;
    tagx->tags = NULL;
    mobi_buffer_seek(buf, 4); /* skip header */
    uint32_t tagx_record_length = mobi_buffer_get32(buf);
    if (tagx_record_length < 12) {
        debug_print("INDX record too short: %u\n", tagx_record_length);
        return MOBI_DATA_CORRUPT;
    }
    tagx->control_byte_count = mobi_buffer_get32(buf);
    tagx_record_length -= 12;
    if (tagx_record_length + buf->offset > buf->maxlen) {
        debug_print("INDX record too long: %u\n", tagx_record_length);
        return MOBI_DATA_CORRUPT;
    }
    tagx->tags = malloc(tagx_record_length * sizeof(TAGXTags));
    if (tagx->tags == NULL) {
        debug_print("%s", "Memory allocation failed for TAGX tags\n");
        return MOBI_MALLOC_FAILED;
    }
    size_t i = 0;
    const size_t tagx_data_length = tagx_record_length / 4;
    size_t control_byte_count = 0;
    while (i < tagx_data_length) {
        tagx->tags[i].tag = mobi_buffer_get8(buf);
        tagx->tags[i].values_count = mobi_buffer_get8(buf);
        tagx->tags[i].bitmask = mobi_buffer_get8(buf);
        const uint8_t control_byte = mobi_buffer_get8(buf);
        if (control_byte) { control_byte_count++; }
        tagx->tags[i].control_byte = control_byte;
        debug_print("tagx[%zu]:\t%i\t%i\t%i\t%i\n", i, tagx->tags[i].tag, tagx->tags[i].values_count, tagx->tags[i].bitmask, control_byte);
        i++;
    }
    if (tagx->control_byte_count != control_byte_count) {
        debug_print("Wrong count of control bytes: %zu != %zu\n", tagx->control_byte_count, control_byte_count);
        free(tagx->tags);
        tagx->tags = NULL;
        tagx->control_byte_count = 0;
        return MOBI_DATA_CORRUPT;
    }
    tagx->tags_count = i;
    return MOBI_SUCCESS;
}


size_t mobi_get_rawlink_location(const MOBIRawml *rawml, const uint32_t pos_fid, const uint32_t pos_off) {
    if (!rawml || !rawml->frag || !rawml->frag->entries ) {
        debug_print("%s", "Initialization failed\n");
        return SIZE_MAX;
    }
    if (pos_fid >= rawml->frag->entries_count) {
        debug_print("%s", "pos_fid not found\n");
        return SIZE_MAX;
    }
    const MOBIIndexEntry *entry = &rawml->frag->entries[pos_fid];
    const size_t insert_position = strtoul(entry->label, NULL, 10);
    size_t file_offset = insert_position + pos_off;
    return file_offset;
}


MOBI_RET mobi_parse_rawml_opt(MOBIRawml *rawml, const MOBIData *m, bool parse_toc, bool parse_dict, bool reconstruct) {

    MOBI_RET ret;
    if (m == NULL) {
        debug_print("%s", "Mobi structure not initialized\n");
        return MOBI_INIT_FAILED;
    }
    if (rawml == NULL) {
        return MOBI_INIT_FAILED;
    }

    /* Get maximal size of text data */
    const size_t maxlen = mobi_get_text_maxsize(m);
    if (maxlen == MOBI_NOTSET) {
        debug_print("%s", "Insane text length\n");
        return MOBI_DATA_CORRUPT;
    }
    char *text = malloc(maxlen + 1);
    if (text == NULL) {
        debug_print("%s", "Memory allocation failed\n");
        return MOBI_MALLOC_FAILED;
    }
    /* Extract text records, unpack, merge and copy it to text string */
    size_t length = maxlen;
    ret = mobi_get_rawml(m, text, &length);
    if (ret != MOBI_SUCCESS) {
        debug_print("%s", "Error parsing text\n");
        free(text);
        return ret;
    }

    if (mobi_exists_fdst(m)) {
        /* Skip parsing if section count less or equal than 1 */
        if (m->mh->fdst_section_count && *m->mh->fdst_section_count > 1) {
            ret = mobi_parse_fdst(m, rawml);
            if (ret != MOBI_SUCCESS) {
                free(text);
                return ret;
            }
        }
    }
    ret = mobi_reconstruct_flow(rawml, text, length);
    free(text);
    if (ret != MOBI_SUCCESS) {
        return ret;
    }
    ret = mobi_reconstruct_resources(m, rawml);
    if (ret != MOBI_SUCCESS) {
        return ret;
    }
    const size_t offset = mobi_get_kf8offset(m);
    /* skeleton index */
    if (mobi_exists_skel_indx(m) && mobi_exists_frag_indx(m)) {
        const size_t indx_record_number = *m->mh->skeleton_index + offset;
        /* to be freed in mobi_free_rawml */
        MOBIIndx *skel_meta = mobi_init_indx();
        ret = mobi_parse_index(m, skel_meta, indx_record_number);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
        rawml->skel = skel_meta;
    }

    /* fragment index */
    if (mobi_exists_frag_indx(m)) {
        MOBIIndx *frag_meta = mobi_init_indx();
        const size_t indx_record_number = *m->mh->fragment_index + offset;
        ret = mobi_parse_index(m, frag_meta, indx_record_number);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
        rawml->frag = frag_meta;
    }

    if (parse_toc) {
        /* guide index */
        if (mobi_exists_guide_indx(m)) {
            MOBIIndx *guide_meta = mobi_init_indx();
            const size_t indx_record_number = *m->mh->guide_index + offset;
            ret = mobi_parse_index(m, guide_meta, indx_record_number);
            if (ret != MOBI_SUCCESS) {
                return ret;
            }
            rawml->guide = guide_meta;
        }

        /* ncx index */
        if (mobi_exists_ncx(m)) {
            MOBIIndx *ncx_meta = mobi_init_indx();
            const size_t indx_record_number = *m->mh->ncx_index + offset;
            ret = mobi_parse_index(m, ncx_meta, indx_record_number);
            if (ret != MOBI_SUCCESS) {
                return ret;
            }
            rawml->ncx = ncx_meta;
        }
    }

    if (parse_dict && mobi_is_dictionary(m)) {
        /* orth */
        MOBIIndx *orth_meta = mobi_init_indx();
        size_t indx_record_number = *m->mh->orth_index + offset;
        ret = mobi_parse_index(m, orth_meta, indx_record_number);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
        rawml->orth = orth_meta;
        /* infl */
        if (mobi_exists_infl(m)) {
            MOBIIndx *infl_meta = mobi_init_indx();
            indx_record_number = *m->mh->infl_index + offset;
            ret = mobi_parse_index(m, infl_meta, indx_record_number);
            if (ret != MOBI_SUCCESS) {
                return ret;
            }
            rawml->infl = infl_meta;
        }
    }

    ret = mobi_reconstruct_parts(rawml);
    if (ret != MOBI_SUCCESS) {
        return ret;
    }
    if (reconstruct) {
#ifdef USE_XMLWRITER
        ret = mobi_build_opf(rawml, m);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
#endif
        ret = mobi_reconstruct_links(rawml);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
        if (mobi_is_kf8(m)) {
            debug_print("Stripping unneeded tags%s", "\n");
            ret = mobi_iterate_txtparts(rawml, mobi_strip_mobitags);
            if (ret != MOBI_SUCCESS) {
                return ret;
            }
        }

    }
    if (mobi_is_cp1252(m)) {
        debug_print("Converting cp1252 to utf8%s", "\n");
        ret = mobi_iterate_txtparts(rawml, mobi_markup_to_utf8);
        if (ret != MOBI_SUCCESS) {
            return ret;
        }
    }
    return MOBI_SUCCESS;
}


static int compat_get_prm(int drive,
			  struct compat_floppy_struct __user *arg)
{
	struct compat_floppy_struct v;
	struct floppy_struct *p;
	int err;

	memset(&v, 0, sizeof(v));
	mutex_lock(&floppy_mutex);
	err = get_floppy_geometry(drive, ITYPE(drive_state[drive].fd_device),
				  &p);
	if (err) {
		mutex_unlock(&floppy_mutex);
		return err;
	}
	memcpy(&v, p, offsetof(struct floppy_struct, name));
	mutex_unlock(&floppy_mutex);
	if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
		return -EFAULT;
	return 0;
}


static void show_floppy(int fdc)
{
	int i;

	pr_info("\n");
	pr_info("floppy driver state\n");
	pr_info("-------------------\n");
	pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%ps\n",
		jiffies, interruptjiffies, jiffies - interruptjiffies,
		lasthandler);

	pr_info("timeout_message=%s\n", timeout_message);
	pr_info("last output bytes:\n");
	for (i = 0; i < OLOGSIZE; i++)
		pr_info("%2x %2x %lu\n",
			output_log[(i + output_log_pos) % OLOGSIZE].data,
			output_log[(i + output_log_pos) % OLOGSIZE].status,
			output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
	pr_info("last result at %lu\n", resultjiffies);
	pr_info("last redo_fd_request at %lu\n", lastredo);
	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
		       reply_buffer, resultsize, true);

	pr_info("status=%x\n", fdc_inb(fdc, FD_STATUS));
	pr_info("fdc_busy=%lu\n", fdc_busy);
	if (do_floppy)
		pr_info("do_floppy=%ps\n", do_floppy);
	if (work_pending(&floppy_work))
		pr_info("floppy_work.func=%ps\n", floppy_work.func);
	if (delayed_work_pending(&fd_timer))
		pr_info("delayed work.function=%p expires=%ld\n",
		       fd_timer.work.func,
		       fd_timer.timer.expires - jiffies);
	if (delayed_work_pending(&fd_timeout))
		pr_info("timer_function=%p expires=%ld\n",
		       fd_timeout.work.func,
		       fd_timeout.timer.expires - jiffies);

	pr_info("cont=%p\n", cont);
	pr_info("current_req=%p\n", current_req);
	pr_info("command_status=%d\n", command_status);
	pr_info("\n");
}


static void floppy_start(void)
{
	reschedule_timeout(current_drive, "floppy start");

	scandrives();
	debug_dcl(drive_params[current_drive].flags,
		  "setting NEWCHANGE in floppy_start\n");
	set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
	floppy_ready();
}


static int compat_getdrvprm(int drive,
			    struct compat_floppy_drive_params __user *arg)
{
	struct compat_floppy_drive_params v;

	memset(&v, 0, sizeof(struct compat_floppy_drive_params));
	mutex_lock(&floppy_mutex);
	v.cmos = drive_params[drive].cmos;
	v.max_dtr = drive_params[drive].max_dtr;
	v.hlt = drive_params[drive].hlt;
	v.hut = drive_params[drive].hut;
	v.srt = drive_params[drive].srt;
	v.spinup = drive_params[drive].spinup;
	v.spindown = drive_params[drive].spindown;
	v.spindown_offset = drive_params[drive].spindown_offset;
	v.select_delay = drive_params[drive].select_delay;
	v.rps = drive_params[drive].rps;
	v.tracks = drive_params[drive].tracks;
	v.timeout = drive_params[drive].timeout;
	v.interleave_sect = drive_params[drive].interleave_sect;
	v.max_errors = drive_params[drive].max_errors;
	v.flags = drive_params[drive].flags;
	v.read_track = drive_params[drive].read_track;
	memcpy(v.autodetect, drive_params[drive].autodetect,
	       sizeof(v.autodetect));
	v.checkfreq = drive_params[drive].checkfreq;
	v.native_format = drive_params[drive].native_format;
	mutex_unlock(&floppy_mutex);

	if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
		return -EFAULT;
	return 0;
}


static int make_raw_rw_request(void)
{
	int aligned_sector_t;
	int max_sector;
	int max_size;
	int tracksize;
	int ssize;

	if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
		return 0;

	set_fdc((long)current_req->q->disk->private_data);

	raw_cmd = &default_raw_cmd;
	raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
	raw_cmd->cmd_count = NR_RW;
	if (rq_data_dir(current_req) == READ) {
		raw_cmd->flags |= FD_RAW_READ;
		raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
	} else if (rq_data_dir(current_req) == WRITE) {
		raw_cmd->flags |= FD_RAW_WRITE;
		raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_WRITE);
	} else {
		DPRINT("%s: unknown command\n", __func__);
		return 0;
	}

	max_sector = _floppy->sect * _floppy->head;

	raw_cmd->cmd[TRACK] = (int)blk_rq_pos(current_req) / max_sector;
	fsector_t = (int)blk_rq_pos(current_req) % max_sector;
	if (_floppy->track && raw_cmd->cmd[TRACK] >= _floppy->track) {
		if (blk_rq_cur_sectors(current_req) & 1) {
			current_count_sectors = 1;
			return 1;
		} else
			return 0;
	}
	raw_cmd->cmd[HEAD] = fsector_t / _floppy->sect;

	if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
	     test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags)) &&
	    fsector_t < _floppy->sect)
		max_sector = _floppy->sect;

	/* 2M disks have phantom sectors on the first track */
	if ((_floppy->rate & FD_2M) && (!raw_cmd->cmd[TRACK]) && (!raw_cmd->cmd[HEAD])) {
		max_sector = 2 * _floppy->sect / 3;
		if (fsector_t >= max_sector) {
			current_count_sectors =
			    min_t(int, _floppy->sect - fsector_t,
				  blk_rq_sectors(current_req));
			return 1;
		}
		raw_cmd->cmd[SIZECODE] = 2;
	} else
		raw_cmd->cmd[SIZECODE] = FD_SIZECODE(_floppy);
	raw_cmd->rate = _floppy->rate & 0x43;
	if ((_floppy->rate & FD_2M) &&
	    (raw_cmd->cmd[TRACK] || raw_cmd->cmd[HEAD]) && raw_cmd->rate == 2)
		raw_cmd->rate = 1;

	if (raw_cmd->cmd[SIZECODE])
		raw_cmd->cmd[SIZECODE2] = 0xff;
	else
		raw_cmd->cmd[SIZECODE2] = 0x80;
	raw_cmd->track = raw_cmd->cmd[TRACK] << STRETCH(_floppy);
	raw_cmd->cmd[DR_SELECT] = UNIT(current_drive) + PH_HEAD(_floppy, raw_cmd->cmd[HEAD]);
	raw_cmd->cmd[GAP] = _floppy->gap;
	ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
	raw_cmd->cmd[SECT_PER_TRACK] = _floppy->sect << 2 >> raw_cmd->cmd[SIZECODE];
	raw_cmd->cmd[SECTOR] = ((fsector_t % _floppy->sect) << 2 >> raw_cmd->cmd[SIZECODE]) +
	    FD_SECTBASE(_floppy);

	/* tracksize describes the size which can be filled up with sectors
	 * of size ssize.
	 */
	tracksize = _floppy->sect - _floppy->sect % ssize;
	if (tracksize < _floppy->sect) {
		raw_cmd->cmd[SECT_PER_TRACK]++;
		if (tracksize <= fsector_t % _floppy->sect)
			raw_cmd->cmd[SECTOR]--;

		/* if we are beyond tracksize, fill up using smaller sectors */
		while (tracksize <= fsector_t % _floppy->sect) {
			while (tracksize + ssize > _floppy->sect) {
				raw_cmd->cmd[SIZECODE]--;
				ssize >>= 1;
			}
			raw_cmd->cmd[SECTOR]++;
			raw_cmd->cmd[SECT_PER_TRACK]++;
			tracksize += ssize;
		}
		max_sector = raw_cmd->cmd[HEAD] * _floppy->sect + tracksize;
	} else if (!raw_cmd->cmd[TRACK] && !raw_cmd->cmd[HEAD] && !(_floppy->rate & FD_2M) && probing) {
		max_sector = _floppy->sect;
	} else if (!raw_cmd->cmd[HEAD] && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
		/* for virtual DMA bug workaround */
		max_sector = _floppy->sect;
	}

	in_sector_offset = (fsector_t % _floppy->sect) % ssize;
	aligned_sector_t = fsector_t - in_sector_offset;
	max_size = blk_rq_sectors(current_req);
	if ((raw_cmd->track == buffer_track) &&
	    (current_drive == buffer_drive) &&
	    (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
		/* data already in track buffer */
		if (CT(raw_cmd->cmd[COMMAND]) == FD_READ) {
			copy_buffer(1, max_sector, buffer_max);
			return 1;
		}
	} else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
		if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
			unsigned int sectors;

			sectors = fsector_t + blk_rq_sectors(current_req);
			if (sectors > ssize && sectors < ssize + ssize)
				max_size = ssize + ssize;
			else
				max_size = ssize;
		}
		raw_cmd->flags &= ~FD_RAW_WRITE;
		raw_cmd->flags |= FD_RAW_READ;
		raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
	}

	if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
		max_size = max_sector;	/* unbounded */

	/* claim buffer track if needed */
	if (buffer_track != raw_cmd->track ||	/* bad track */
	    buffer_drive != current_drive ||	/* bad drive */
	    fsector_t > buffer_max ||
	    fsector_t < buffer_min ||
	    ((CT(raw_cmd->cmd[COMMAND]) == FD_READ ||
	      (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
	     max_sector > 2 * max_buffer_sectors + buffer_min &&
	     max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
		/* not enough space */
		buffer_track = -1;
		buffer_drive = current_drive;
		buffer_max = buffer_min = aligned_sector_t;
	}
	raw_cmd->kernel_data = floppy_track_buffer +
		((aligned_sector_t - buffer_min) << 9);

	if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
		/* copy write buffer to track buffer.
		 * if we get here, we know that the write
		 * is either aligned or the data already in the buffer
		 * (buffer will be overwritten) */
		if (in_sector_offset && buffer_track == -1)
			DPRINT("internal error offset !=0 on write\n");
		buffer_track = raw_cmd->track;
		buffer_drive = current_drive;
		copy_buffer(ssize, max_sector,
			    2 * max_buffer_sectors + buffer_min);
	} else
		transfer_size(ssize, max_sector,
			      2 * max_buffer_sectors + buffer_min -
			      aligned_sector_t);

	/* round up current_count_sectors to get dma xfer size */
	raw_cmd->length = in_sector_offset + current_count_sectors;
	raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
	raw_cmd->length <<= 9;
	if ((raw_cmd->length < current_count_sectors << 9) ||
	    (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE &&
	     (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
	      aligned_sector_t < buffer_min)) ||
	    raw_cmd->length % (128 << raw_cmd->cmd[SIZECODE]) ||
	    raw_cmd->length <= 0 || current_count_sectors <= 0) {
		DPRINT("fractionary current count b=%lx s=%lx\n",
		       raw_cmd->length, current_count_sectors);
		pr_info("addr=%d, length=%ld\n",
			(int)((raw_cmd->kernel_data -
			       floppy_track_buffer) >> 9),
			current_count_sectors);
		pr_info("st=%d ast=%d mse=%d msi=%d\n",
			fsector_t, aligned_sector_t, max_sector, max_size);
		pr_info("ssize=%x SIZECODE=%d\n", ssize, raw_cmd->cmd[SIZECODE]);
		pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
			raw_cmd->cmd[COMMAND], raw_cmd->cmd[SECTOR],
			raw_cmd->cmd[HEAD], raw_cmd->cmd[TRACK]);
		pr_info("buffer drive=%d\n", buffer_drive);
		pr_info("buffer track=%d\n", buffer_track);
		pr_info("buffer_min=%d\n", buffer_min);
		pr_info("buffer_max=%d\n", buffer_max);
		return 0;
	}

	if (raw_cmd->kernel_data < floppy_track_buffer ||
	    current_count_sectors < 0 ||
	    raw_cmd->length < 0 ||
	    raw_cmd->kernel_data + raw_cmd->length >
	    floppy_track_buffer + (max_buffer_sectors << 10)) {
		DPRINT("buffer overrun in schedule dma\n");
		pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
			fsector_t, buffer_min, raw_cmd->length >> 9);
		pr_info("current_count_sectors=%ld\n",
			current_count_sectors);
		if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
			pr_info("read\n");
		if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE)
			pr_info("write\n");
		return 0;
	}
	if (raw_cmd->length == 0) {
		DPRINT("zero dma transfer attempted from make_raw_request\n");
		return 0;
	}

	virtualdmabug_workaround();
	return 2;
}


static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE],
		int native_format)
{
	size_t floppy_type_size = ARRAY_SIZE(floppy_type);
	size_t i = 0;

	for (i = 0; i < FD_AUTODETECT_SIZE; ++i) {
		if (autodetect[i] < 0 ||
		    autodetect[i] >= floppy_type_size)
			return false;
	}

	if (native_format < 0 || native_format >= floppy_type_size)
		return false;

	return true;
}


static int floppy_grab_irq_and_dma(void)
{
	int fdc;

	if (atomic_inc_return(&usage_count) > 1)
		return 0;

	/*
	 * We might have scheduled a free_irq(), wait it to
	 * drain first:
	 */
	flush_workqueue(floppy_wq);

	if (fd_request_irq()) {
		DPRINT("Unable to grab IRQ%d for the floppy driver\n",
		       FLOPPY_IRQ);
		atomic_dec(&usage_count);
		return -1;
	}
	if (fd_request_dma()) {
		DPRINT("Unable to grab DMA%d for the floppy driver\n",
		       FLOPPY_DMA);
		if (can_use_virtual_dma & 2)
			use_virtual_dma = can_use_virtual_dma = 1;
		if (!(can_use_virtual_dma & 1)) {
			fd_free_irq();
			atomic_dec(&usage_count);
			return -1;
		}
	}

	for (fdc = 0; fdc < N_FDC; fdc++) {
		if (fdc_state[fdc].address != -1) {
			if (floppy_request_regions(fdc))
				goto cleanup;
		}
	}
	for (fdc = 0; fdc < N_FDC; fdc++) {
		if (fdc_state[fdc].address != -1) {
			reset_fdc_info(fdc, 1);
			fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
		}
	}

	set_dor(0, ~0, 8);	/* avoid immediate interrupt */

	for (fdc = 0; fdc < N_FDC; fdc++)
		if (fdc_state[fdc].address != -1)
			fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
	/*
	 * The driver will try and free resources and relies on us
	 * to know if they were allocated or not.
	 */
	current_fdc = 0;
	irqdma_allocated = 1;
	return 0;
cleanup:
	fd_free_irq();
	fd_free_dma();
	while (--fdc >= 0)
		floppy_release_regions(fdc);
	current_fdc = 0;
	atomic_dec(&usage_count);
	return -1;
}


static void request_done(int uptodate)
{
	struct request *req = current_req;
	int block;
	char msg[sizeof("request done ") + sizeof(int) * 3];

	probing = 0;
	snprintf(msg, sizeof(msg), "request done %d", uptodate);
	reschedule_timeout(MAXTIMEOUT, msg);

	if (!req) {
		pr_info("floppy.c: no request in request_done\n");
		return;
	}

	if (uptodate) {
		/* maintain values for invalidation on geometry
		 * change */
		block = current_count_sectors + blk_rq_pos(req);
		INFBOUND(drive_state[current_drive].maxblock, block);
		if (block > _floppy->sect)
			drive_state[current_drive].maxtrack = 1;

		floppy_end_request(req, 0);
	} else {
		if (rq_data_dir(req) == WRITE) {
			/* record write error information */
			write_errors[current_drive].write_errors++;
			if (write_errors[current_drive].write_errors == 1) {
				write_errors[current_drive].first_error_sector = blk_rq_pos(req);
				write_errors[current_drive].first_error_generation = drive_state[current_drive].generation;
			}
			write_errors[current_drive].last_error_sector = blk_rq_pos(req);
			write_errors[current_drive].last_error_generation = drive_state[current_drive].generation;
		}
		floppy_end_request(req, BLK_STS_IOERR);
	}
}


static void twaddle(int fdc, int drive)
{
	if (drive_params[drive].select_delay)
		return;
	fdc_outb(fdc_state[fdc].dor & ~(0x10 << UNIT(drive)),
		 fdc, FD_DOR);
	fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
	drive_state[drive].select_date = jiffies;
}


NAN_METHOD(XmlDocument::SetDtd)
{
    Nan::HandleScope scope;

    XmlDocument* document = Nan::ObjectWrap::Unwrap<XmlDocument>(info.Holder());
    assert(document);

    Nan::Utf8String name(info[0]);

    v8::Local<v8::Value> extIdOpt;
    v8::Local<v8::Value> sysIdOpt;
    if (info.Length() > 1 && info[1]->IsString()) {
      extIdOpt = info[1];
    }
    if (info.Length() > 2 && info[2]->IsString()) {
      sysIdOpt = info[2];
    }

    Nan::Utf8String extIdRaw(extIdOpt);
    Nan::Utf8String sysIdRaw(sysIdOpt);

    //must be set to null in order for xmlCreateIntSubset to ignore them
    const char* extId = (extIdRaw.length()) ? *extIdRaw : NULL;
    const char* sysId = (sysIdRaw.length()) ? *sysIdRaw : NULL;

    //No good way of unsetting the doctype if it is previously set...this allows us to.
    xmlDtdPtr dtd = xmlGetIntSubset(document->xml_obj);

    xmlUnlinkNode((xmlNodePtr) dtd);
    xmlFreeNode((xmlNodePtr) dtd);

    xmlCreateIntSubset(document->xml_obj, (const xmlChar *) *name, (const xmlChar *) extId, (const xmlChar *) sysId);

    return info.GetReturnValue().Set(info.Holder());
}


NAN_METHOD(XmlDocument::ToString)
{
    Nan::HandleScope scope;

    XmlDocument* document = Nan::ObjectWrap::Unwrap<XmlDocument>(info.Holder());
    assert(document);

    int options = 0;

    if (info.Length() > 0) {
    if (info[0]->IsBoolean()) {
        if (Nan::To<v8::Boolean>(info[0]).ToLocalChecked()->Value() == true) {
            options |= XML_SAVE_FORMAT;
        }
    } else if (info[0]->IsObject()) {
        v8::Local<v8::Object> obj = Nan::To<v8::Object>(info[0]).ToLocalChecked();

        // drop the xml declaration
        if (Nan::Get(obj, Nan::New<v8::String>("declaration").ToLocalChecked()).ToLocalChecked()->IsFalse()) {
            options |= XML_SAVE_NO_DECL;
        }

        // format save output
        if (Nan::Get(obj, Nan::New<v8::String>("format").ToLocalChecked()).ToLocalChecked()->IsTrue()) {
            options |= XML_SAVE_FORMAT;
        }

        // no empty tags (only works with XML) ex: <title></title> becomes <title/>
        if (Nan::Get(obj, Nan::New<v8::String>("selfCloseEmpty").ToLocalChecked()).ToLocalChecked()->IsFalse()) {
            options |= XML_SAVE_NO_EMPTY;
        }

        // format with non-significant whitespace
        if (Nan::Get(obj, Nan::New<v8::String>("whitespace").ToLocalChecked()).ToLocalChecked()->IsTrue()) {
            options |= XML_SAVE_WSNONSIG;
        }

        v8::Local<v8::Value> type = Nan::Get(obj, Nan::New<v8::String>("type").ToLocalChecked()).ToLocalChecked();
        if (Nan::Equals(type, Nan::New<v8::String>("XML").ToLocalChecked()).ToChecked() ||
            Nan::Equals(type, Nan::New<v8::String>("xml").ToLocalChecked()).ToChecked()) {
            options |= XML_SAVE_AS_XML;    // force XML serialization on HTML doc
        } else if (Nan::Equals(type, Nan::New<v8::String>("HTML").ToLocalChecked()).ToChecked() ||
                 Nan::Equals(type, Nan::New<v8::String>("html").ToLocalChecked()).ToChecked()) {
            options |= XML_SAVE_AS_HTML;   // force HTML serialization on XML doc
            // if the document is XML and we want formatted HTML output
            // we must use the XHTML serializer because the default HTML
            // serializer only formats node->type = HTML_NODE and not XML_NODEs
            if ((options & XML_SAVE_FORMAT) && (options & XML_SAVE_XHTML) == false) {
              options |= XML_SAVE_XHTML;
            }
        } else if (Nan::Equals(type, Nan::New<v8::String>("XHTML").ToLocalChecked()).ToChecked() ||
                 Nan::Equals(type, Nan::New<v8::String>("xhtml").ToLocalChecked()).ToChecked()) {
                options |= XML_SAVE_XHTML;    // force XHTML serialization
            }
        }
    }

    xmlBuffer* buf = xmlBufferCreate();
    xmlSaveCtxt* savectx = xmlSaveToBuffer(buf, "UTF-8", options);
    xmlSaveTree(savectx, (xmlNode*)document->xml_obj);
    xmlSaveFlush(savectx);
    xmlSaveClose(savectx);
    v8::Local<v8::Value> ret = Nan::Null();
    if (xmlBufferLength(buf) > 0)
        ret = Nan::New<v8::String>((char*)xmlBufferContent(buf), xmlBufferLength(buf)).ToLocalChecked();
    xmlBufferFree(buf);

    return info.GetReturnValue().Set(ret);
}


void Statement::Finalize_(Baton* b) {
    std::unique_ptr<Baton> baton(b);
    Napi::Env env = baton->stmt->Env();
    Napi::HandleScope scope(env);

    baton->stmt->Finalize_();

    // Fire callback in case there was one.
    Napi::Function cb = baton->callback.Value();
    if (!cb.IsUndefined() && cb.IsFunction()) {
        TRY_CATCH_CALL(baton->stmt->Value(), cb, 0, NULL);
    }
}


void Statement::AsyncEach(uv_async_t* handle) {
    Async* async = static_cast<Async*>(handle->data);

    Napi::Env env = async->stmt->Env();
    Napi::HandleScope scope(env);

    while (true) {
        // Get the contents out of the data cache for us to process in the JS callback.
        Rows rows;
        NODE_SQLITE3_MUTEX_LOCK(&async->mutex)
        rows.swap(async->data);
        NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex)

        if (rows.empty()) {
            break;
        }

        Napi::Function cb = async->item_cb.Value();
        if (!cb.IsUndefined() && cb.IsFunction()) {
            Napi::Value argv[2];
            argv[0] = env.Null();

            Rows::const_iterator it = rows.begin();
            Rows::const_iterator end = rows.end();
            for (int i = 0; it < end; ++it, i++) {
                std::unique_ptr<Row> row(*it);
                argv[1] = RowToJS(env,row.get());
                async->retrieved++;
                TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv);
            }
        }
    }

    Napi::Function cb = async->completed_cb.Value();
    if (async->completed) {
        if (!cb.IsEmpty() &&
                cb.IsFunction()) {
            Napi::Value argv[] = {
                env.Null(),
                Napi::Number::New(env, async->retrieved)
            };
            TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv);
        }
        uv_close(reinterpret_cast<uv_handle_t*>(handle), CloseCallback);
    }
}


void Statement::Work_BeginEach(Baton* baton) {
    // Only create the Async object when we're actually going into
    // the event loop. This prevents dangling events.
    EachBaton* each_baton = static_cast<EachBaton*>(baton);
    each_baton->async = new Async(each_baton->stmt, reinterpret_cast<uv_async_cb>(AsyncEach));
    each_baton->async->item_cb.Reset(each_baton->callback.Value(), 1);
    each_baton->async->completed_cb.Reset(each_baton->completed.Value(), 1);

    STATEMENT_BEGIN(Each);
}


bool OtherInstanceOf(Napi::Object source, const char* object_type) {
    if (strncmp(object_type, "Date", 4) == 0) {
        return source.InstanceOf(source.Env().Global().Get("Date").As<Function>());
    } else if (strncmp(object_type, "RegExp", 6) == 0) {
        return source.InstanceOf(source.Env().Global().Get("RegExp").As<Function>());
    }

    return false;
}


Napi::Value Statement::Run(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    Statement* stmt = this;

    Baton* baton = stmt->Bind<RunBaton>(info);
    if (baton == NULL) {
        Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException();
        return env.Null();
    }
    else {
        stmt->Schedule(Work_BeginRun, baton);
        return info.This();
    }
}


void Statement::Schedule(Work_Callback callback, Baton* baton) {
    if (finalized) {
        queue.push(new Call(callback, baton));
        CleanQueue();
    }
    else if (!prepared || locked) {
        queue.push(new Call(callback, baton));
    }
    else {
        callback(baton);
    }
}


static void io_wq_submit_work(struct io_wq_work *work)
{
	struct io_kiocb *req = container_of(work, struct io_kiocb, work);
	const struct io_op_def *def = &io_op_defs[req->opcode];
	unsigned int issue_flags = IO_URING_F_UNLOCKED;
	bool needs_poll = false;
	struct io_kiocb *timeout;
	int ret = 0, err = -ECANCELED;

	/* one will be dropped by ->io_free_work() after returning to io-wq */
	if (!(req->flags & REQ_F_REFCOUNT))
		__io_req_set_refcount(req, 2);
	else
		req_ref_get(req);

	timeout = io_prep_linked_timeout(req);
	if (timeout)
		io_queue_linked_timeout(timeout);

	/* either cancelled or io-wq is dying, so don't touch tctx->iowq */
	if (work->flags & IO_WQ_WORK_CANCEL) {
fail:
		io_req_task_queue_fail(req, err);
		return;
	}
	if (!io_assign_file(req, issue_flags)) {
		err = -EBADF;
		work->flags |= IO_WQ_WORK_CANCEL;
		goto fail;
	}

	if (req->flags & REQ_F_FORCE_ASYNC) {
		bool opcode_poll = def->pollin || def->pollout;

		if (opcode_poll && file_can_poll(req->file)) {
			needs_poll = true;
			issue_flags |= IO_URING_F_NONBLOCK;
		}
	}

	do {
		ret = io_issue_sqe(req, issue_flags);
		if (ret != -EAGAIN)
			break;
		/*
		 * We can get EAGAIN for iopolled IO even though we're
		 * forcing a sync submission from here, since we can't
		 * wait for request slots on the block side.
		 */
		if (!needs_poll) {
			cond_resched();
			continue;
		}

		if (io_arm_poll_handler(req, issue_flags) == IO_APOLL_OK)
			return;
		/* aborted or ready, in either case retry blocking */
		needs_poll = false;
		issue_flags &= ~IO_URING_F_NONBLOCK;
	} while (1);

	/* avoid locking problems by failing it from a clean context */
	if (ret)
		io_req_task_queue_fail(req, ret);


 */
static int io_poll_check_events(struct io_kiocb *req, bool locked)
{
	struct io_ring_ctx *ctx = req->ctx;
	int v;

	/* req->task == current here, checking PF_EXITING is safe */
	if (unlikely(req->task->flags & PF_EXITING))
		io_poll_mark_cancelled(req);

	do {
		v = atomic_read(&req->poll_refs);

		/* tw handler should be the owner, and so have some references */
		if (WARN_ON_ONCE(!(v & IO_POLL_REF_MASK)))
			return 0;
		if (v & IO_POLL_CANCEL_FLAG)
			return -ECANCELED;

		if (!req->result) {
			struct poll_table_struct pt = { ._key = req->apoll_events };
			unsigned flags = locked ? 0 : IO_URING_F_UNLOCKED;

			if (unlikely(!io_assign_file(req, flags)))
				return -EBADF;
			req->result = vfs_poll(req->file, &pt) & req->apoll_events;
		}

		/* multishot, just fill an CQE and proceed */
		if (req->result && !(req->apoll_events & EPOLLONESHOT)) {
			__poll_t mask = mangle_poll(req->result & req->apoll_events);
			bool filled;

			spin_lock(&ctx->completion_lock);
			filled = io_fill_cqe_aux(ctx, req->user_data, mask,
						 IORING_CQE_F_MORE);
			io_commit_cqring(ctx);
			spin_unlock(&ctx->completion_lock);
			if (unlikely(!filled))
				return -ECANCELED;
			io_cqring_ev_posted(ctx);
		} else if (req->result) {
			return 0;
		}

		/*
		 * Release all references, retry if someone tried to restart
		 * task_work while we were executing it.
		 */
	} while (atomic_sub_return(v & IO_POLL_REF_MASK, &req->poll_refs));

	return 1;


static int io_ringfd_unregister(struct io_ring_ctx *ctx, void __user *__arg,
				unsigned nr_args)
{
	struct io_uring_rsrc_update __user *arg = __arg;
	struct io_uring_task *tctx = current->io_uring;
	struct io_uring_rsrc_update reg;
	int ret = 0, i;

	if (!nr_args || nr_args > IO_RINGFD_REG_MAX)
		return -EINVAL;
	if (!tctx)
		return 0;

	for (i = 0; i < nr_args; i++) {
		if (copy_from_user(&reg, &arg[i], sizeof(reg))) {
			ret = -EFAULT;
			break;
		}
		if (reg.resv || reg.offset >= IO_RINGFD_REG_MAX) {
			ret = -EINVAL;
			break;
		}

		reg.offset = array_index_nospec(reg.offset, IO_RINGFD_REG_MAX);
		if (tctx->registered_rings[reg.offset]) {
			fput(tctx->registered_rings[reg.offset]);
			tctx->registered_rings[reg.offset] = NULL;
		}
	}

	return i ? i : ret;


void DL_Dxf::writeHatch2(DL_WriterA& dw,
                         const DL_HatchData& data,
                         const DL_Attributes& /*attrib*/) {

    dw.dxfInt(75, 0);                // odd parity
    dw.dxfInt(76, 1);                // pattern type
    if (data.solid==false) {
        dw.dxfReal(52, data.angle);
        dw.dxfReal(41, data.scale);
        dw.dxfInt(77, 0);            // not double
        //dw.dxfInt(78, 0);
        dw.dxfInt(78, 1);
        dw.dxfReal(53, 45.0);
        dw.dxfReal(43, 0.0);
        dw.dxfReal(44, 0.0);
        dw.dxfReal(45, -0.0883883476483184);
        dw.dxfReal(46, 0.0883883476483185);
        dw.dxfInt(79, 0);
    }
    dw.dxfInt(98, 0);

    if (version==DL_VERSION_2000) {
        dw.dxfString(1001, "ACAD");
        dw.dxfReal(1010, data.originX);
        dw.dxfReal(1020, data.originY);
        dw.dxfInt(1030, 0.0);
    }
}


void DL_Dxf::writeDimAngular2L(DL_WriterA& dw,
                             const DL_DimensionData& data,
                             const DL_DimAngular2LData& edata,
                             const DL_Attributes& attrib) {

    dw.entity("DIMENSION");

    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbEntity");
    }
    dw.entityAttributes(attrib);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbDimension");
    }

    dw.dxfReal(10, data.dpx);
    dw.dxfReal(20, data.dpy);
    dw.dxfReal(30, data.dpz);

    dw.dxfReal(11, data.mpx);
    dw.dxfReal(21, data.mpy);
    dw.dxfReal(31, 0.0);

    dw.dxfInt(70, data.type);
    if (version>DL_VERSION_R12) {
        dw.dxfInt(71, data.attachmentPoint);
        dw.dxfInt(72, data.lineSpacingStyle); // opt
        dw.dxfInt(74, data.arrow1Flipped);
        dw.dxfInt(75, data.arrow2Flipped);
        dw.dxfReal(41, data.lineSpacingFactor); // opt
    }

    dw.dxfReal(42, data.angle);

    dw.dxfString(1, data.text);   // opt
    //dw.dxfString(3, data.style);
    dw.dxfString(3, "Standard");

    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDb2LineAngularDimension");
    }

    dw.dxfReal(13, edata.dpx1);
    dw.dxfReal(23, edata.dpy1);
    dw.dxfReal(33, 0.0);

    dw.dxfReal(14, edata.dpx2);
    dw.dxfReal(24, edata.dpy2);
    dw.dxfReal(34, 0.0);

    dw.dxfReal(15, edata.dpx3);
    dw.dxfReal(25, edata.dpy3);
    dw.dxfReal(35, 0.0);

    dw.dxfReal(16, edata.dpx4);
    dw.dxfReal(26, edata.dpy4);
    dw.dxfReal(36, 0.0);
}


void DL_Dxf::writeBlockRecord(DL_WriterA& dw) {
    dw.dxfString(  0, "TABLE");
    dw.dxfString(  2, "BLOCK_RECORD");
    if (version==DL_VERSION_2000) {
        dw.dxfHex(5, 1);
    }
    //dw.dxfHex(330, 0);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbSymbolTable");
    }
    dw.dxfInt( 70, 1);

    dw.dxfString(  0, "BLOCK_RECORD");
    if (version==DL_VERSION_2000) {
        dw.dxfHex(5, 0x1F);
    }
    //int msh = dw.handle();
    //dw.setModelSpaceHandle(msh);
    //dw.dxfHex(330, 1);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbSymbolTableRecord");
        dw.dxfString(100, "AcDbBlockTableRecord");
    }
    dw.dxfString(  2, "*Model_Space");
    dw.dxfHex(340, 0x22);

    dw.dxfString(  0, "BLOCK_RECORD");
    if (version==DL_VERSION_2000) {
        dw.dxfHex(5, 0x1B);
    }
    //int psh = dw.handle();
    //dw.setPaperSpaceHandle(psh);
    //dw.dxfHex(330, 1);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbSymbolTableRecord");
        dw.dxfString(100, "AcDbBlockTableRecord");
    }
    dw.dxfString(  2, "*Paper_Space");
    dw.dxfHex(340, 0x1E);

    dw.dxfString(  0, "BLOCK_RECORD");
    if (version==DL_VERSION_2000) {
        dw.dxfHex(5, 0x23);
    }
    //int ps0h = dw.handle();
    //dw.setPaperSpace0Handle(ps0h);
    //dw.dxfHex(330, 1);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbSymbolTableRecord");
        dw.dxfString(100, "AcDbBlockTableRecord");
    }
    dw.dxfString(  2, "*Paper_Space0");
    dw.dxfHex(340, 0x26);

    //dw.dxfString(  0, "ENDTAB");
}


void DL_Dxf::writeUcs(DL_WriterA& dw) {
    dw.dxfString(  0, "TABLE");
    dw.dxfString(  2, "UCS");
    if (version==DL_VERSION_2000) {
        dw.dxfHex(5, 7);
    }
    //dw.dxfHex(330, 0);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbSymbolTable");
    }
    dw.dxfInt( 70, 0);
    dw.dxfString(  0, "ENDTAB");
}


void DL_Dxf::writeInsert(DL_WriterA& dw,
                         const DL_InsertData& data,
                         const DL_Attributes& attrib) {

    if (data.name.empty()) {
        std::cerr << "DL_Dxf::writeInsert: "
        << "Block name must not be empty\n";
        return;
    }

    dw.entity("INSERT");
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbEntity");
    }
    dw.entityAttributes(attrib);
    if (version==DL_VERSION_2000) {
        if (data.cols!=1 || data.rows!=1) {
            dw.dxfString(100, "AcDbMInsertBlock");
        }
        else {
            dw.dxfString(100, "AcDbBlockReference");
        }
    }
    dw.dxfString(2, data.name);
    dw.dxfReal(10, data.ipx);
    dw.dxfReal(20, data.ipy);
    dw.dxfReal(30, data.ipz);
    if (data.sx!=1.0 || data.sy!=1.0) {
        dw.dxfReal(41, data.sx);
        dw.dxfReal(42, data.sy);
        dw.dxfReal(43, 1.0);
    }
    if (data.angle!=0.0) {
        dw.dxfReal(50, data.angle);
    }
    if (data.cols!=1 || data.rows!=1) {
        dw.dxfInt(70, data.cols);
        dw.dxfInt(71, data.rows);
    }
    if (data.colSp!=0.0 || data.rowSp!=0.0) {
        dw.dxfReal(44, data.colSp);
        dw.dxfReal(45, data.rowSp);
    }
}


DL_WriterA* DL_Dxf::out(const char* file, DL_Codes::version version) {
    char* f = new char[strlen(file)+1];
    strcpy(f, file);
    this->version = version;

    DL_WriterA* dw = new DL_WriterA(f, version);
    if (dw->openFailed()) {
        delete dw;
        delete[] f;
        return NULL;
    } else {
        delete[] f;
        return dw;
    }
}


bool DL_Dxf::in(std::istream& stream,
                DL_CreationInterface* creationInterface) {

    if (stream.good()) {
        firstCall=true;
        currentObjectType = DL_UNKNOWN;
        while (readDxfGroups(stream, creationInterface)) {}
        return true;
    }
    return false;
}


void DL_Dxf::addDimAngular(DL_CreationInterface* creationInterface) {
    DL_DimensionData d = getDimData();

    // angular dimension:
    DL_DimAngular2LData da(
        // definition point 1
        getRealValue(13, 0.0),
        getRealValue(23, 0.0),
        getRealValue(33, 0.0),
        // definition point 2
        getRealValue(14, 0.0),
        getRealValue(24, 0.0),
        getRealValue(34, 0.0),
        // definition point 3
        getRealValue(15, 0.0),
        getRealValue(25, 0.0),
        getRealValue(35, 0.0),
        // definition point 4
        getRealValue(16, 0.0),
        getRealValue(26, 0.0),
        getRealValue(36, 0.0));
    creationInterface->addDimAngular(d, da);
}


bool DL_Dxf::handleSplineData(DL_CreationInterface* /*creationInterface*/) {
    // Allocate Spline knots (group code 72):
    if (groupCode==72) {
        maxKnots = toInt(groupValue);
        if (maxKnots>0) {
            if (knots!=NULL) {
                delete[] knots;
            }
            knots = new double[maxKnots];
            for (int i=0; i<maxKnots; ++i) {
                knots[i] = 0.0;
            }
        }
        knotIndex=-1;
        return true;
    }

    // Allocate Spline control points / weights (group code 73):
    else if (groupCode==73) {
        maxControlPoints = toInt(groupValue);
        if (maxControlPoints>0) {
            if (controlPoints!=NULL) {
                delete[] controlPoints;
            }
            if (weights!=NULL) {
                delete[] weights;
            }
            controlPoints = new double[3*maxControlPoints];
            weights = new double[maxControlPoints];
            for (int i=0; i<maxControlPoints; ++i) {
                controlPoints[i*3] = 0.0;
                controlPoints[i*3+1] = 0.0;
                controlPoints[i*3+2] = 0.0;
                weights[i] = 1.0;
            }
        }
        controlPointIndex=-1;
        weightIndex=-1;
        return true;
    }

    // Allocate Spline fit points (group code 74):
    else if (groupCode==74) {
        maxFitPoints = toInt(groupValue);
        if (maxFitPoints>0) {
            if (fitPoints!=NULL) {
                delete[] fitPoints;
            }
            fitPoints = new double[3*maxFitPoints];
            for (int i=0; i<maxFitPoints; ++i) {
                fitPoints[i*3] = 0.0;
                fitPoints[i*3+1] = 0.0;
                fitPoints[i*3+2] = 0.0;
            }
        }
        fitPointIndex=-1;
        return true;
    }

    // Process spline knot vertices (group code 40):
    else if (groupCode==40) {
        if (knotIndex<maxKnots-1) {
            knotIndex++;
            knots[knotIndex] = toReal(groupValue);
        }
        return true;
    }

    // Process spline control points (group codes 10/20/30):
    else if (groupCode==10 || groupCode==20 ||
             groupCode==30) {

        if (controlPointIndex<maxControlPoints-1 && groupCode==10) {
            controlPointIndex++;
        }

        if (controlPointIndex>=0 && controlPointIndex<maxControlPoints) {
            controlPoints[3*controlPointIndex + (groupCode/10-1)] = toReal(groupValue);
        }
        return true;
    }

    // Process spline fit points (group codes 11/21/31):
    else if (groupCode==11 || groupCode==21 || groupCode==31) {
        if (fitPointIndex<maxFitPoints-1 && groupCode==11) {
            fitPointIndex++;
        }

        if (fitPointIndex>=0 && fitPointIndex<maxFitPoints) {
            fitPoints[3*fitPointIndex + ((groupCode-1)/10-1)] = toReal(groupValue);
        }
        return true;
    }

    // Process spline weights (group code 41)
    else if (groupCode==41) {

        if (weightIndex<maxControlPoints-1) {
            weightIndex++;
        }

        if (weightIndex>=0 && weightIndex<maxControlPoints) {
            weights[weightIndex] = toReal(groupValue);
        }
        return true;
    }
    return false;
}


void DL_Dxf::writeHeader(DL_WriterA& dw) {
    dw.comment("dxflib " DL_VERSION);
    dw.sectionHeader();

    dw.dxfString(9, "$ACADVER");
    switch (version) {
    case DL_Codes::AC1009:
        dw.dxfString(1, "AC1009");
        break;
    case DL_Codes::AC1012:
        dw.dxfString(1, "AC1012");
        break;
    case DL_Codes::AC1014:
        dw.dxfString(1, "AC1014");
        break;
    case DL_Codes::AC1015:
        dw.dxfString(1, "AC1015");
        break;
    case DL_Codes::AC1009_MIN:
        // minimalistic DXF version is unidentified in file:
        break;
    }

    // Newer version require that (otherwise a*cad crashes..)
    if (version==DL_VERSION_2000) {
        dw.dxfString(9, "$HANDSEED");
        dw.dxfHex(5, 0xFFFF);
    }

    // commented out: more variables can be added after that by caller:
    //dw.sectionEnd();
}


void DL_Dxf::writeDimLinear(DL_WriterA& dw,
                            const DL_DimensionData& data,
                            const DL_DimLinearData& edata,
                            const DL_Attributes& attrib) {

    dw.entity("DIMENSION");

    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbEntity");
    }
    dw.entityAttributes(attrib);
    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbDimension");
    }

    dw.dxfReal(10, data.dpx);
    dw.dxfReal(20, data.dpy);
    dw.dxfReal(30, data.dpz);

    dw.dxfReal(11, data.mpx);
    dw.dxfReal(21, data.mpy);
    dw.dxfReal(31, 0.0);

    dw.dxfInt(70, data.type);
    if (version>DL_VERSION_R12) {
        dw.dxfInt(71, data.attachmentPoint);
        dw.dxfInt(72, data.lineSpacingStyle); // opt
        dw.dxfInt(74, data.arrow1Flipped);
        dw.dxfInt(75, data.arrow2Flipped);
        dw.dxfReal(41, data.lineSpacingFactor); // opt
    }

    dw.dxfReal(42, data.angle);

    dw.dxfString(1, data.text);   // opt
    //dw.dxfString(3, data.style);
    dw.dxfString(3, "Standard");

    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbAlignedDimension");
    }

    dw.dxfReal(13, edata.dpx1);
    dw.dxfReal(23, edata.dpy1);
    dw.dxfReal(33, 0.0);

    dw.dxfReal(14, edata.dpx2);
    dw.dxfReal(24, edata.dpy2);
    dw.dxfReal(34, 0.0);

    dw.dxfReal(50, edata.angle/(2.0*M_PI)*360.0);

    if (version==DL_VERSION_2000) {
        dw.dxfString(100, "AcDbRotatedDimension");
    }

    writeDimStyleOverrides(dw, data);
}


check_fstab(const char *progname, const char *mountpoint, const char *devname,
	    char **options)
{
	FILE *fstab;
	struct mntent *mnt;
	size_t len;

	/* make sure this mount is listed in /etc/fstab */
	fstab = setmntent(_PATH_MNTTAB, "r");
	if (!fstab) {
		fprintf(stderr, "Couldn't open %s for reading!\n", _PATH_MNTTAB);
		return EX_FILEIO;
	}

	while ((mnt = getmntent(fstab))) {
		len = strlen(mnt->mnt_dir);
		while (len > 1) {
		        if (mnt->mnt_dir[len - 1] == '/')
			        mnt->mnt_dir[len - 1] = '\0';
		        else
				break;
			len--;
		}
		if (!strcmp(mountpoint, mnt->mnt_dir))
			break;
	}
	endmntent(fstab);

	if (mnt == NULL || strcmp(mnt->mnt_fsname, devname)) {
		fprintf(stderr, "%s: permission denied: no match for "
			"%s found in %s\n", progname, mountpoint, _PATH_MNTTAB);
		return EX_USAGE;
	}

	/*
	 * 'mount' munges the options from fstab before passing them
	 * to us. It is non-trivial to test that we have the correct
	 * set of options. We don't want to trust what the user
	 * gave us, so just take whatever is in /etc/fstab.
	 */
	*options = strdup(mnt->mnt_opts);
	return 0;
}


   will override this setting for that string.  */
void TTF_ByteSwappedUNICODE(SDL_bool swapped)
{
    TTF_byteswapped = swapped;


void TTF_CloseFont(TTF_Font *font)
{
    if (font) {
#if TTF_USE_HARFBUZZ
        hb_font_destroy(font->hb_font);
#endif
        Flush_Cache(font);
        if (font->face) {
            FT_Done_Face(font->face);
        }
        if (font->args.stream) {
            SDL_free(font->args.stream);
        }
        if (font->freesrc) {
            SDL_RWclose(font->src);
        }
        if (font->pos_buf) {
            SDL_free(font->pos_buf);
        }
        SDL_free(font);
    }


TTF_Font* TTF_OpenFont(const char *file, int ptsize)
{
    return TTF_OpenFontIndex(file, ptsize, 0);


TTF_Font* TTF_OpenFontIndexDPI( const char *file, int ptsize, long index, unsigned int hdpi, unsigned int vdpi )
{
    SDL_RWops *rw = SDL_RWFromFile(file, "rb");
    if ( rw == NULL ) {
        return NULL;
    }
    return TTF_OpenFontIndexDPIRW(rw, 1, ptsize, index, hdpi, vdpi);


int TTF_Init(void)
{
    int status = 0;

/* Some debug to know how it gets compiled */
#if 0
    int duffs = 0, sse2 = 0, neon = 0, compil_sse2 = 0, compil_neon = 0;
#  if defined(USE_DUFFS_LOOP)
    duffs = 1;
#  endif
#  if defined(HAVE_SSE2_INTRINSICS)
    sse2 = hasSSE2();
    compil_sse2 = 1;
#  endif
#  if defined(HAVE_NEON_INTRINSICS)
    neon = hasNEON();
    compil_neon = 1;
#  endif
    SDL_Log("SDL_ttf: hasSSE2=%d hasNEON=%d alignment=%d duffs_loop=%d compil_sse2=%d compil_neon=%d",
            sse2, neon, Get_Alignement(), duffs, compil_sse2, compil_neon);

    SDL_Log("Sizeof TTF_Image: %d c_glyph: %d TTF_Font: %d", sizeof (TTF_Image), sizeof (c_glyph), sizeof (TTF_Font));
#endif

    if (!TTF_initialized) {
        FT_Error error = FT_Init_FreeType(&library);
        if (error) {
            TTF_SetFTError("Couldn't init FreeType engine", error);
            status = -1;
        }
    }
    if (status == 0) {
        ++TTF_initialized;
#if TTF_USE_SDF
#  if 0
        /* Set various properties of the renderers. */
        int spread = 4;
        int overlaps = 0;
        FT_Property_Set( library, "bsdf", "spread", &spread);
        FT_Property_Set( library, "sdf", "spread", &spread);
        FT_Property_Set( library, "sdf", "overlaps", &overlaps);
#  endif
#endif
    }
    return status;


void TTF_SetFontKerning(TTF_Font *font, int allowed)
{
    font->allow_kerning = allowed;
    font->use_kerning   = allowed && FT_HAS_KERNING(font->face);


static SDL_INLINE void BG_32(const TTF_Image *image, Uint8 *destination, Sint32 srcskip, Uint32 dstskip)
{
    const Uint32 *src    = (Uint32 *)image->buffer;
    Uint32       *dst    = (Uint32 *)destination;
    Uint32        width  = image->width / 4;
    Uint32        height = image->rows;

    while (height--) {
        /* *INDENT-OFF* */
        DUFFS_LOOP4(
            *dst++ |= *src++;
        , width);
        /* *INDENT-ON* */
        src = (const Uint32 *)((const Uint8 *)src + srcskip);
        dst = (Uint32 *)((Uint8 *)dst + dstskip);
    }
}


static void clip_glyph(int *_x, int *_y, TTF_Image *image, const SDL_Surface *textbuf)
{
    int above_w;
    int above_h;
    int x = *_x;
    int y = *_y;

    int srcbpp = 1;
    if (image->is_color) {
        /* This isn't tested because colored image never ends up left clipped */
        srcbpp = 4;
    }

    /* Don't go below x=0 */
    if (x < 0) {
        int tmp = -x;
        x = 0;
        image->width  -= tmp;
        image->buffer += srcbpp * tmp;
    }
    /* Don't go above textbuf->w */
    above_w = x + image->width - textbuf->w;
    if (above_w > 0) {
        image->width -= above_w;
    }
    /* Don't go below y=0 */
    if (y < 0) {
        int tmp = -y;
        y = 0;
        image->rows   -= tmp;
        image->buffer += tmp * image->pitch;
    }
    /* Don't go above textbuf->h */
    above_h = y + image->rows - textbuf->h;
    if (above_h > 0) {
        image->rows -= above_h;
    }
    /* Could be negative if (x > textbuf->w), or if (x + width < 0) */
    image->width = SDL_max(0, image->width);
    image->rows  = SDL_max(0, image->rows);

    /* After 'image->width' clipping:
     * Make sure 'rows' is also 0, so it doesn't break USE_DUFFS_LOOP */
    if (image->width == 0) {
        image->rows = 0;
    }

    *_x = x;
    *_y = y;
}


int TTF_GlyphIsProvided(TTF_Font *font, Uint16 ch)
{
    return (int)get_char_index(font, ch);


int TTF_FontHeight(const TTF_Font *font)
{
    return font->height;


int TTF_GlyphIsProvided32(TTF_Font *font, Uint32 ch)
{
    return (int)get_char_index(font, ch);


static SDL_INLINE void BG_Blended_Color(const TTF_Image *image, Uint32 *destination, Sint32 srcskip, Uint32 dstskip, Uint8 fg_alpha)
{
    const Uint32 *src   = (Uint32 *)image->buffer;
    Uint32      *dst    = destination;
    Uint32       width  = image->width;
    Uint32       height = image->rows;

    if (fg_alpha == 0) { /* SDL_ALPHA_OPAQUE */
        while (height--) {
            /* *INDENT-OFF* */
            DUFFS_LOOP4(
                *dst++ = *src++;
            , width);
            /* *INDENT-ON* */
            src = (const Uint32 *)((const Uint8 *)src + srcskip);
            dst = (Uint32 *)((Uint8 *)dst + dstskip);
        }
    } else {
        Uint32 alpha;
        Uint32 tmp;

        while (height--) {
            /* *INDENT-OFF* */
            DUFFS_LOOP4(
                    tmp = *src++;
                    alpha = tmp >> 24;
                    tmp &= ~0xFF000000;
                    alpha = fg_alpha * alpha;
                    alpha =  DIVIDE_BY_255(alpha) << 24;
                    *dst++ = tmp | alpha
                    , width);
            /* *INDENT-ON* */
            src = (const Uint32 *)((const Uint8 *)src + srcskip);
            dst = (Uint32 *)((Uint8 *)dst + dstskip);
        }
    }
}


static SDL_Surface* Create_Surface_Solid(int width, int height, SDL_Color fg, Uint32 *color)
{
    const int alignment = Get_Alignement() - 1;
    SDL_Surface *textbuf;
    Sint64 size;

    /* Create a surface with memory:
     * - pitch is rounded to alignment
     * - adress is aligned
     */
    void *pixels, *ptr;
    /* Worse case at the end of line pulling 'alignment' extra blank pixels */
    Sint64 pitch = (Sint64)width + (Sint64)alignment;
    pitch += alignment;
    pitch &= ~alignment;
    size = height * pitch + sizeof (void *) + alignment;
    if (size < 0 || size > SDL_MAX_SINT32) {
        /* Overflow... */
        return NULL;
    }

    ptr = SDL_malloc((size_t)size);
    if (ptr == NULL) {
        return NULL;
    }

    /* address is aligned */
    pixels = (void *)(((uintptr_t)ptr + sizeof(void *) + alignment) & ~alignment);
    ((void **)pixels)[-1] = ptr;

    textbuf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, 0, pitch, SDL_PIXELFORMAT_INDEX8);
    if (textbuf == NULL) {
        SDL_free(ptr);
        return NULL;
    }

    /* Let SDL handle the memory allocation */
    textbuf->flags &= ~SDL_PREALLOC;
    textbuf->flags |= SDL_SIMD_ALIGNED;

    /* Initialize with background to 0 */
    SDL_memset(pixels, 0, height * pitch);

    /* Underline/Strikethrough color style */
    *color = 1;

    /* Fill the palette: 1 is foreground */
    {
        SDL_Palette *palette = textbuf->format->palette;
        palette->colors[0].r = 255 - fg.r;
        palette->colors[0].g = 255 - fg.g;
        palette->colors[0].b = 255 - fg.b;
        palette->colors[1].r = fg.r;
        palette->colors[1].g = fg.g;
        palette->colors[1].b = fg.b;
        palette->colors[1].a = fg.a;
    }

    SDL_SetColorKey(textbuf, SDL_TRUE, 0);

    return textbuf;


xmlBufBackToBuffer(xmlBufPtr buf) {
    xmlBufferPtr ret;

    if (buf == NULL)
        return(NULL);
    CHECK_COMPAT(buf)
    if ((buf->error) || (buf->buffer == NULL)) {
        xmlBufFree(buf);
        return(NULL);
    }

    ret = buf->buffer;
    /*
     * What to do in case of error in the buffer ???
     */
    if (buf->use > INT_MAX) {
        /*
         * Worse case, we really allocated and used more than the
         * maximum allowed memory for an xmlBuffer on this architecture.
         * Keep the buffer but provide a truncated size value.
         */
        xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
        ret->use = INT_MAX;
        ret->size = INT_MAX;
    } else if (buf->size > INT_MAX) {
        /*
         * milder case, we allocated more than the maximum allowed memory
         * for an xmlBuffer on this architecture, but used less than the
         * limit.
         * Keep the buffer but provide a truncated size value.
         */
        xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
        ret->use = (int) buf->use;
        ret->size = INT_MAX;
    } else {
        ret->use = (int) buf->use;
        ret->size = (int) buf->size;
    }
    ret->alloc = buf->alloc;
    ret->content = buf->content;
    ret->contentIO = buf->contentIO;
    xmlFree(buf);
    return(ret);
}


xmlBufCreateSize(size_t size) {
    xmlBufPtr ret;

    if (size == SIZE_MAX)
        return(NULL);
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
    if (ret == NULL) {
	xmlBufMemoryError(NULL, "creating buffer");
        return(NULL);
    }
    ret->use = 0;
    ret->error = 0;
    ret->buffer = NULL;
    ret->alloc = xmlBufferAllocScheme;
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
    UPDATE_COMPAT(ret);
    if (ret->size){
        ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
        if (ret->content == NULL) {
	    xmlBufMemoryError(ret, "creating buffer");
            xmlFree(ret);
            return(NULL);
        }
        ret->content[0] = 0;
    } else
	ret->content = NULL;
    ret->contentIO = NULL;
    return(ret);
}


xmlBufFromBuffer(xmlBufferPtr buffer) {
    xmlBufPtr ret;

    if (buffer == NULL)
        return(NULL);

    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
    if (ret == NULL) {
	xmlBufMemoryError(NULL, "creating buffer");
        return(NULL);
    }
    ret->use = buffer->use;
    ret->size = buffer->size;
    UPDATE_COMPAT(ret);
    ret->error = 0;
    ret->buffer = buffer;
    ret->alloc = buffer->alloc;
    ret->content = buffer->content;
    ret->contentIO = buffer->contentIO;

    return(ret);
}


xmlBufferCCat(xmlBufferPtr buf, const char *str) {
    return xmlBufferCat(buf, (const xmlChar *) str);
}


xmlBufferCreateSize(size_t size) {
    xmlBufferPtr ret;

    if (size >= UINT_MAX)
        return(NULL);
    ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
    if (ret == NULL) {
	xmlTreeErrMemory("creating buffer");
        return(NULL);
    }
    ret->use = 0;
    ret->alloc = xmlBufferAllocScheme;
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
    if (ret->size){
        ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
        if (ret->content == NULL) {
	    xmlTreeErrMemory("creating buffer");
            xmlFree(ret);
            return(NULL);
        }
        ret->content[0] = 0;
    } else
	ret->content = NULL;
    ret->contentIO = NULL;
    return(ret);
}


static SQInteger table_getdelegate(HSQUIRRELVM v)
{
    return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR;
}


static SQInteger base_dummy(HSQUIRRELVM SQ_UNUSED_ARG(v))
{
    return 0;
}


static SQInteger closure_pcall(HSQUIRRELVM v)
{
    return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;
}


static SQInteger thread_getstackinfos(HSQUIRRELVM v)
{
    SQObjectPtr o = stack_get(v,1);
    if(sq_type(o) == OT_THREAD) {
        SQVM *thread = _thread(o);
        SQInteger threadtop = sq_gettop(thread);
        SQInteger level;
        sq_getinteger(v,-1,&level);
        SQRESULT res = __getcallstackinfos(thread,level);
        if(SQ_FAILED(res))
        {
            sq_settop(thread,threadtop);
            if(sq_type(thread->_lasterror) == OT_STRING) {
                sq_throwerror(v,_stringval(thread->_lasterror));
            }
            else {
                sq_throwerror(v,_SC("unknown error"));
            }
        }
        if(res > 0) {
            //some result
            sq_move(v,thread,-1);
            sq_settop(thread,threadtop);
            return 1;
        }
        //no result
        sq_settop(thread,threadtop);
        return 0;

    }
    return sq_throwerror(v,_SC("wrong parameter"));
}


static SQInteger array_find(HSQUIRRELVM v)
{
    SQObject &o = stack_get(v,1);
    SQObjectPtr &val = stack_get(v,2);
    SQArray *a = _array(o);
    SQInteger size = a->Size();
    SQObjectPtr temp;
    for(SQInteger n = 0; n < size; n++) {
        bool res = false;
        a->Get(n,temp);
        if(SQVM::IsEqual(temp,val,res) && res) {
            v->Push(n);
            return 1;
        }
    }
    return 0;
}


static SQInteger base_resurectureachable(HSQUIRRELVM v)
{
    sq_resurrectunreachable(v);
    return 1;
}


static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
{
    if(func < 0) {
        if(!v->ObjCmp(a,b,ret)) return false;
    }
    else {
        SQInteger top = sq_gettop(v);
        sq_push(v, func);
        sq_pushroottable(v);
        v->Push(a);
        v->Push(b);
		SQObjectPtr *valptr = arr->_values._vals;
		SQUnsignedInteger precallsize = arr->_values.size();
        if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {
            if(!sq_isstring( v->_lasterror))
                v->Raise_Error(_SC("compare func failed"));
            return false;
        }
		if(SQ_FAILED(sq_getinteger(v, -1, &ret))) {
            v->Raise_Error(_SC("numeric value expected as return value of the compare function"));
            return false;
        }
		if (precallsize != arr->_values.size() || valptr != arr->_values._vals) {
			v->Raise_Error(_SC("array resized during sort operation"));
			return false;
		}
        sq_settop(v, top);
        return true;
    }
    return true;
}


free_buf_options(
    buf_T	*buf,
    int		free_p_ff)
{
    if (free_p_ff)
    {
	clear_string_option(&buf->b_p_fenc);
	clear_string_option(&buf->b_p_ff);
	clear_string_option(&buf->b_p_bh);
	clear_string_option(&buf->b_p_bt);
    }
#ifdef FEAT_FIND_ID
    clear_string_option(&buf->b_p_def);
    clear_string_option(&buf->b_p_inc);
# ifdef FEAT_EVAL
    clear_string_option(&buf->b_p_inex);
# endif
#endif
#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
    clear_string_option(&buf->b_p_inde);
    clear_string_option(&buf->b_p_indk);
#endif
#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
    clear_string_option(&buf->b_p_bexpr);
#endif
#if defined(FEAT_CRYPT)
    clear_string_option(&buf->b_p_cm);
#endif
    clear_string_option(&buf->b_p_fp);
#if defined(FEAT_EVAL)
    clear_string_option(&buf->b_p_fex);
#endif
#ifdef FEAT_CRYPT
# ifdef FEAT_SODIUM
    if ((buf->b_p_key != NULL) && (*buf->b_p_key != NUL) &&
				(crypt_get_method_nr(buf) == CRYPT_M_SOD))
	crypt_sodium_munlock(buf->b_p_key, STRLEN(buf->b_p_key));
# endif
    clear_string_option(&buf->b_p_key);
#endif
    clear_string_option(&buf->b_p_kp);
    clear_string_option(&buf->b_p_mps);
    clear_string_option(&buf->b_p_fo);
    clear_string_option(&buf->b_p_flp);
    clear_string_option(&buf->b_p_isk);
#ifdef FEAT_VARTABS
    clear_string_option(&buf->b_p_vsts);
    vim_free(buf->b_p_vsts_nopaste);
    buf->b_p_vsts_nopaste = NULL;
    VIM_CLEAR(buf->b_p_vsts_array);
    clear_string_option(&buf->b_p_vts);
    VIM_CLEAR(buf->b_p_vts_array);
#endif
#ifdef FEAT_KEYMAP
    clear_string_option(&buf->b_p_keymap);
    keymap_clear(&buf->b_kmap_ga);
    ga_clear(&buf->b_kmap_ga);
#endif
    clear_string_option(&buf->b_p_com);
#ifdef FEAT_FOLDING
    clear_string_option(&buf->b_p_cms);
#endif
    clear_string_option(&buf->b_p_nf);
#ifdef FEAT_SYN_HL
    clear_string_option(&buf->b_p_syn);
    clear_string_option(&buf->b_s.b_syn_isk);
#endif
#ifdef FEAT_SPELL
    clear_string_option(&buf->b_s.b_p_spc);
    clear_string_option(&buf->b_s.b_p_spf);
    vim_regfree(buf->b_s.b_cap_prog);
    buf->b_s.b_cap_prog = NULL;
    clear_string_option(&buf->b_s.b_p_spl);
    clear_string_option(&buf->b_s.b_p_spo);
#endif
#ifdef FEAT_SEARCHPATH
    clear_string_option(&buf->b_p_sua);
#endif
    clear_string_option(&buf->b_p_ft);
#ifdef FEAT_CINDENT
    clear_string_option(&buf->b_p_cink);
    clear_string_option(&buf->b_p_cino);
    clear_string_option(&buf->b_p_cinsd);
#endif
#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
    clear_string_option(&buf->b_p_cinw);
#endif
    clear_string_option(&buf->b_p_cpt);
#ifdef FEAT_COMPL_FUNC
    clear_string_option(&buf->b_p_cfu);
    free_callback(&buf->b_cfu_cb);
    clear_string_option(&buf->b_p_ofu);
    free_callback(&buf->b_ofu_cb);
    clear_string_option(&buf->b_p_tsrfu);
    free_callback(&buf->b_tsrfu_cb);
#endif
#ifdef FEAT_QUICKFIX
    clear_string_option(&buf->b_p_gp);
    clear_string_option(&buf->b_p_mp);
    clear_string_option(&buf->b_p_efm);
#endif
    clear_string_option(&buf->b_p_ep);
    clear_string_option(&buf->b_p_path);
    clear_string_option(&buf->b_p_tags);
    clear_string_option(&buf->b_p_tc);
#ifdef FEAT_EVAL
    clear_string_option(&buf->b_p_tfu);
    free_callback(&buf->b_tfu_cb);
#endif
    clear_string_option(&buf->b_p_dict);
    clear_string_option(&buf->b_p_tsr);
#ifdef FEAT_TEXTOBJ
    clear_string_option(&buf->b_p_qe);
#endif
    buf->b_p_ar = -1;
    buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
#ifdef FEAT_LISP
    clear_string_option(&buf->b_p_lw);
#endif
    clear_string_option(&buf->b_p_bkc);
    clear_string_option(&buf->b_p_menc);
}


close_buffer(
    win_T	*win,		// if not NULL, set b_last_cursor
    buf_T	*buf,
    int		action,
    int		abort_if_last,
    int		ignore_abort)
{
    int		is_curbuf;
    int		nwindows;
    bufref_T	bufref;
    int		is_curwin = (curwin != NULL && curwin->w_buffer == buf);
    win_T	*the_curwin = curwin;
    tabpage_T	*the_curtab = curtab;
    int		unload_buf = (action != 0);
    int		wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE);
    int		del_buf = (action == DOBUF_DEL || wipe_buf);

    CHECK_CURBUF;

    // Force unloading or deleting when 'bufhidden' says so.
    // The caller must take care of NOT deleting/freeing when 'bufhidden' is
    // "hide" (otherwise we could never free or delete a buffer).
    if (buf->b_p_bh[0] == 'd')		// 'bufhidden' == "delete"
    {
	del_buf = TRUE;
	unload_buf = TRUE;
    }
    else if (buf->b_p_bh[0] == 'w')	// 'bufhidden' == "wipe"
    {
	del_buf = TRUE;
	unload_buf = TRUE;
	wipe_buf = TRUE;
    }
    else if (buf->b_p_bh[0] == 'u')	// 'bufhidden' == "unload"
	unload_buf = TRUE;

#ifdef FEAT_TERMINAL
    if (bt_terminal(buf) && (buf->b_nwindows == 1 || del_buf))
    {
	CHECK_CURBUF;
	if (term_job_running(buf->b_term))
	{
	    if (wipe_buf || unload_buf)
	    {
		if (!can_unload_buffer(buf))
		    return FALSE;

		// Wiping out or unloading a terminal buffer kills the job.
		free_terminal(buf);
	    }
	    else
	    {
		// The job keeps running, hide the buffer.
		del_buf = FALSE;
		unload_buf = FALSE;
	    }
	}
	else if (buf->b_p_bh[0] == 'h' && !del_buf)
	{
	    // Hide a terminal buffer.
	    unload_buf = FALSE;
	}
	else
	{
	    // A terminal buffer is wiped out if the job has finished.
	    del_buf = TRUE;
	    unload_buf = TRUE;
	    wipe_buf = TRUE;
	}
	CHECK_CURBUF;
    }
#endif

    // Disallow deleting the buffer when it is locked (already being closed or
    // halfway a command that relies on it). Unloading is allowed.
    if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
	return FALSE;

    // check no autocommands closed the window
    if (win != NULL && win_valid_any_tab(win))
    {
	// Set b_last_cursor when closing the last window for the buffer.
	// Remember the last cursor position and window options of the buffer.
	// This used to be only for the current window, but then options like
	// 'foldmethod' may be lost with a ":only" command.
	if (buf->b_nwindows == 1)
	    set_last_cursor(win);
	buflist_setfpos(buf, win,
		    win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
		    win->w_cursor.col, TRUE);
    }

    set_bufref(&bufref, buf);

    // When the buffer is no longer in a window, trigger BufWinLeave
    if (buf->b_nwindows == 1)
    {
	++buf->b_locked;
	++buf->b_locked_split;
	if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
								  FALSE, buf)
		&& !bufref_valid(&bufref))
	{
	    // Autocommands deleted the buffer.
aucmd_abort:
	    emsg(_(e_autocommands_caused_command_to_abort));
	    return FALSE;
	}
	--buf->b_locked;
	--buf->b_locked_split;
	if (abort_if_last && one_window())
	    // Autocommands made this the only window.
	    goto aucmd_abort;

	// When the buffer becomes hidden, but is not unloaded, trigger
	// BufHidden
	if (!unload_buf)
	{
	    ++buf->b_locked;
	    ++buf->b_locked_split;
	    if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
								  FALSE, buf)
		    && !bufref_valid(&bufref))
		// Autocommands deleted the buffer.
		goto aucmd_abort;
	    --buf->b_locked;
	    --buf->b_locked_split;
	    if (abort_if_last && one_window())
		// Autocommands made this the only window.
		goto aucmd_abort;
	}
#ifdef FEAT_EVAL
	// autocmds may abort script processing
	if (!ignore_abort && aborting())
	    return FALSE;
#endif
    }

    // If the buffer was in curwin and the window has changed, go back to that
    // window, if it still exists.  This avoids that ":edit x" triggering a
    // "tabnext" BufUnload autocmd leaves a window behind without a buffer.
    if (is_curwin && curwin != the_curwin &&  win_valid_any_tab(the_curwin))
    {
	block_autocmds();
	goto_tabpage_win(the_curtab, the_curwin);
	unblock_autocmds();
    }

    nwindows = buf->b_nwindows;

    // decrease the link count from windows (unless not in any window)
    if (buf->b_nwindows > 0)
	--buf->b_nwindows;

#ifdef FEAT_DIFF
    if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0)
	diff_buf_delete(buf);	// Clear 'diff' for hidden buffer.
#endif

    // Return when a window is displaying the buffer or when it's not
    // unloaded.
    if (buf->b_nwindows > 0 || !unload_buf)
	return FALSE;

    // Always remove the buffer when there is no file name.
    if (buf->b_ffname == NULL)
	del_buf = TRUE;

    // When closing the current buffer stop Visual mode before freeing
    // anything.
    if (buf == curbuf && VIsual_active
#if defined(EXITFREE)
	    && !entered_free_all_mem
#endif
	    )
	end_visual_mode();

    // Free all things allocated for this buffer.
    // Also calls the "BufDelete" autocommands when del_buf is TRUE.
    //
    // Remember if we are closing the current buffer.  Restore the number of
    // windows, so that autocommands in buf_freeall() don't get confused.
    is_curbuf = (buf == curbuf);
    buf->b_nwindows = nwindows;

    buf_freeall(buf, (del_buf ? BFA_DEL : 0)
		   + (wipe_buf ? BFA_WIPE : 0)
		   + (ignore_abort ? BFA_IGNORE_ABORT : 0));

    // Autocommands may have deleted the buffer.
    if (!bufref_valid(&bufref))
	return FALSE;
#ifdef FEAT_EVAL
    // autocmds may abort script processing
    if (!ignore_abort && aborting())
	return FALSE;
#endif

    // It's possible that autocommands change curbuf to the one being deleted.
    // This might cause the previous curbuf to be deleted unexpectedly.  But
    // in some cases it's OK to delete the curbuf, because a new one is
    // obtained anyway.  Therefore only return if curbuf changed to the
    // deleted buffer.
    if (buf == curbuf && !is_curbuf)
	return FALSE;

    if (win_valid_any_tab(win) && win->w_buffer == buf)
	win->w_buffer = NULL;  // make sure we don't use the buffer now

    // Autocommands may have opened or closed windows for this buffer.
    // Decrement the count for the close we do here.
    if (buf->b_nwindows > 0)
	--buf->b_nwindows;

    /*
     * Remove the buffer from the list.
     */
    if (wipe_buf)
    {
	// Do not wipe out the buffer if it is used in a window.
	if (buf->b_nwindows > 0)
	    return FALSE;

	if (action == DOBUF_WIPE_REUSE)
	{
	    // we can re-use this buffer number, store it
	    if (buf_reuse.ga_itemsize == 0)
		ga_init2(&buf_reuse, sizeof(int), 50);
	    if (ga_grow(&buf_reuse, 1) == OK)
		((int *)buf_reuse.ga_data)[buf_reuse.ga_len++] = buf->b_fnum;
	}
	if (buf->b_sfname != buf->b_ffname)
	    VIM_CLEAR(buf->b_sfname);
	else
	    buf->b_sfname = NULL;
	VIM_CLEAR(buf->b_ffname);
	if (buf->b_prev == NULL)
	    firstbuf = buf->b_next;
	else
	    buf->b_prev->b_next = buf->b_next;
	if (buf->b_next == NULL)
	    lastbuf = buf->b_prev;
	else
	    buf->b_next->b_prev = buf->b_prev;
	free_buffer(buf);
    }
    else
    {
	if (del_buf)
	{
	    // Free all internal variables and reset option values, to make
	    // ":bdel" compatible with Vim 5.7.
	    free_buffer_stuff(buf, TRUE);

	    // Make it look like a new buffer.
	    buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;

	    // Init the options when loaded again.
	    buf->b_p_initialized = FALSE;
	}
	buf_clear_file(buf);
	if (del_buf)
	    buf->b_p_bl = FALSE;
    }
    // NOTE: at this point "curbuf" may be invalid!
    return TRUE;
}


stl_remove_unconnected_facets(stl_file *stl) {
  /* A couple of things need to be done here.  One is to remove any */
  /* completely unconnected facets (0 edges connected) since these are */
  /* useless and could be completely wrong.   The second thing that needs to */
  /* be done is to remove any degenerate facets that were created during */
  /* stl_check_facets_nearby(). */

  int i;

  if (stl->error) return;

  /* remove degenerate facets */
  for(i = 0; i < stl->stats.number_of_facets; i++) {
    if(   !memcmp(&stl->facet_start[i].vertex[0],
                  &stl->facet_start[i].vertex[1], sizeof(stl_vertex))
          || !memcmp(&stl->facet_start[i].vertex[1],
                     &stl->facet_start[i].vertex[2], sizeof(stl_vertex))
          || !memcmp(&stl->facet_start[i].vertex[0],
                     &stl->facet_start[i].vertex[2], sizeof(stl_vertex))) {
      stl_remove_degenerate(stl, i);
      i--;
    }
  }

  if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) {
    /* remove completely unconnected facets */
    for(i = 0; i < stl->stats.number_of_facets; i++) {
      if(   (stl->neighbors_start[i].neighbor[0] == -1)
            && (stl->neighbors_start[i].neighbor[1] == -1)
            && (stl->neighbors_start[i].neighbor[2] == -1)) {
        /* This facet is completely unconnected.  Remove it. */
        stl_remove_facet(stl, i);
        i--;
      }
    }
  }
}


static int acrn_dev_open(struct inode *inode, struct file *filp)
{
	struct acrn_vm *vm;

	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
	if (!vm)
		return -ENOMEM;

	vm->vmid = ACRN_INVALID_VMID;
	filp->private_data = vm;
	return 0;
}


flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
{
    char_u	*p;
    unsigned	n;

    switch (flagtype)
    {
	case AFT_CHAR:
	    return vim_strchr(afflist, flag) != NULL;

	case AFT_CAPLONG:
	case AFT_LONG:
	    for (p = afflist; *p != NUL; )
	    {
		n = mb_ptr2char_adv(&p);
		if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z'))
								 && *p != NUL)
		    n = mb_ptr2char_adv(&p) + (n << 16);
		if (n == flag)
		    return TRUE;
	    }
	    break;

	case AFT_NUM:
	    for (p = afflist; *p != NUL; )
	    {
		n = getdigits(&p);
		if (n == 0)
		    n = ZERO_FLAG;
		if (n == flag)
		    return TRUE;
		if (*p != NUL)	// skip over comma
		    ++p;
	    }
	    break;
    }
    return FALSE;
}


init_spellfile(void)
{
    char_u	*buf;
    int		l;
    char_u	*fname;
    char_u	*rtp;
    char_u	*lend;
    int		aspath = FALSE;
    char_u	*lstart = curbuf->b_s.b_p_spl;

    if (*curwin->w_s->b_p_spl != NUL && curwin->w_s->b_langp.ga_len > 0)
    {
	buf = alloc(MAXPATHL);
	if (buf == NULL)
	    return;

	// Find the end of the language name.  Exclude the region.  If there
	// is a path separator remember the start of the tail.
	for (lend = curwin->w_s->b_p_spl; *lend != NUL
			&& vim_strchr((char_u *)",._", *lend) == NULL; ++lend)
	    if (vim_ispathsep(*lend))
	    {
		aspath = TRUE;
		lstart = lend + 1;
	    }

	// Loop over all entries in 'runtimepath'.  Use the first one where we
	// are allowed to write.
	rtp = p_rtp;
	while (*rtp != NUL)
	{
	    if (aspath)
		// Use directory of an entry with path, e.g., for
		// "/dir/lg.utf-8.spl" use "/dir".
		vim_strncpy(buf, curbuf->b_s.b_p_spl,
					    lstart - curbuf->b_s.b_p_spl - 1);
	    else
		// Copy the path from 'runtimepath' to buf[].
		copy_option_part(&rtp, buf, MAXPATHL, ",");
	    if (filewritable(buf) == 2)
	    {
		// Use the first language name from 'spelllang' and the
		// encoding used in the first loaded .spl file.
		if (aspath)
		    vim_strncpy(buf, curbuf->b_s.b_p_spl,
						  lend - curbuf->b_s.b_p_spl);
		else
		{
		    // Create the "spell" directory if it doesn't exist yet.
		    l = (int)STRLEN(buf);
		    vim_snprintf((char *)buf + l, MAXPATHL - l, "/spell");
		    if (filewritable(buf) != 2)
			vim_mkdir(buf, 0755);

		    l = (int)STRLEN(buf);
		    vim_snprintf((char *)buf + l, MAXPATHL - l,
				 "/%.*s", (int)(lend - lstart), lstart);
		}
		l = (int)STRLEN(buf);
		fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
							 ->lp_slang->sl_fname;
		vim_snprintf((char *)buf + l, MAXPATHL - l, ".%s.add",
			fname != NULL
			  && strstr((char *)gettail(fname), ".ascii.") != NULL
				       ? (char_u *)"ascii" : spell_enc());
		set_option_value_give_err((char_u *)"spellfile",
							   0L, buf, OPT_LOCAL);
		break;
	    }
	    aspath = FALSE;
	}

	vim_free(buf);
    }
}


ex_spell(exarg_T *eap)
{
    spell_add_word(eap->arg, (int)STRLEN(eap->arg),
		eap->cmdidx == CMD_spellwrong ? SPELL_ADD_BAD :
		eap->cmdidx == CMD_spellrare ? SPELL_ADD_RARE : SPELL_ADD_GOOD,
				   eap->forceit ? 0 : (int)eap->line2,
				   eap->cmdidx == CMD_spellundo);
}


set_spell_finish(spelltab_T *new_st)
{
    int		i;

    if (did_set_spelltab)
    {
	// check that it's the same table
	for (i = 0; i < 256; ++i)
	{
	    if (spelltab.st_isw[i] != new_st->st_isw[i]
		    || spelltab.st_isu[i] != new_st->st_isu[i]
		    || spelltab.st_fold[i] != new_st->st_fold[i]
		    || spelltab.st_upper[i] != new_st->st_upper[i])
	    {
		emsg(_(e_word_characters_differ_between_spell_files));
		return FAIL;
	    }
	}
    }
    else
    {
	// copy the new spelltab into the one being used
	spelltab = *new_st;
	did_set_spelltab = TRUE;
    }

    return OK;
}


getroom(
    spellinfo_T *spin,
    size_t	len,		// length needed
    int		align)		// align for pointer
{
    char_u	*p;
    sblock_T	*bl = spin->si_blocks;

    if (align && bl != NULL)
	// Round size up for alignment.  On some systems structures need to be
	// aligned to the size of a pointer (e.g., SPARC).
	bl->sb_used = (bl->sb_used + sizeof(char *) - 1)
						      & ~(sizeof(char *) - 1);

    if (bl == NULL || bl->sb_used + len > SBLOCKSIZE)
    {
	if (len >= SBLOCKSIZE)
	    bl = NULL;
	else
	    // Allocate a block of memory. It is not freed until much later.
	    bl = alloc_clear(sizeof(sblock_T) + SBLOCKSIZE);
	if (bl == NULL)
	{
	    if (!spin->si_did_emsg)
	    {
		emsg(_(e_insufficient_memory_word_list_will_be_incomplete));
		spin->si_did_emsg = TRUE;
	    }
	    return NULL;
	}
	bl->sb_next = spin->si_blocks;
	spin->si_blocks = bl;
	bl->sb_used = 0;
	++spin->si_blocks_cnt;
    }

    p = bl->sb_data + bl->sb_used;
    bl->sb_used += (int)len;

    return p;
}


write_spell_prefcond(FILE *fd, garray_T *gap, size_t *fwv)
{
    int		i;
    char_u	*p;
    int		len;
    int		totlen;

    if (fd != NULL)
	put_bytes(fd, (long_u)gap->ga_len, 2);	    // <prefcondcnt>

    totlen = 2 + gap->ga_len; // length of <prefcondcnt> and <condlen> bytes

    for (i = 0; i < gap->ga_len; ++i)
    {
	// <prefcond> : <condlen> <condstr>
	p = ((char_u **)gap->ga_data)[i];
	if (p != NULL)
	{
	    len = (int)STRLEN(p);
	    if (fd != NULL)
	    {
		fputc(len, fd);
		*fwv &= fwrite(p, (size_t)len, (size_t)1, fd);
	    }
	    totlen += len;
	}
	else if (fd != NULL)
	    fputc(0, fd);
    }

    return totlen;
}


find_first_blank(pos_T *posp)
{
    int	    c;

    while (decl(posp) != -1)
    {
	c = gchar_pos(posp);
	if (!VIM_ISWHITE(c))
	{
	    incl(posp);
	    break;
	}
    }
}


find_next_quote(
    char_u	*line,
    int		col,
    int		quotechar,
    char_u	*escape)	// escape characters, can be NULL
{
    int		c;

    for (;;)
    {
	c = line[col];
	if (c == NUL)
	    return -1;
	else if (escape != NULL && vim_strchr(escape, c))
	{
	    ++col;
	    if (line[col] == NUL)
		return -1;
	}
	else if (c == quotechar)
	    break;
	if (has_mbyte)
	    col += (*mb_ptr2len)(line + col);
	else
	    ++col;
    }
    return col;
}


int dbg_remove_all_break(void)
{
	int error;
	int i;

	/* Clear memory breakpoints. */
	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
		if (kgdb_break[i].state != BP_ACTIVE)
			goto setundefined;
		error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
		if (error)
			pr_err("breakpoint remove failed: %lx\n",
			       kgdb_break[i].bpt_addr);
setundefined:
		kgdb_break[i].state = BP_UNDEFINED;
	}

	/* Clear hardware breakpoints. */
	if (arch_kgdb_ops.remove_all_hw_break)
		arch_kgdb_ops.remove_all_hw_break();

	return 0;
}


struct task_struct *kdb_curr_task(int cpu)
{
	struct task_struct *p = curr_task(cpu);
#ifdef	_TIF_MCA_INIT
	if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && KDB_TSK(cpu))
		p = krp->p;
#endif
	return p;
}


int kdb_parse(const char *cmdstr)
{
	static char *argv[MAXARGC];
	static int argc;
	static char cbuf[CMD_BUFLEN+2];
	char *cp;
	char *cpp, quoted;
	kdbtab_t *tp;
	int escaped, ignore_errors = 0, check_grep = 0;

	/*
	 * First tokenize the command string.
	 */
	cp = (char *)cmdstr;

	if (KDB_FLAG(CMD_INTERRUPT)) {
		/* Previous command was interrupted, newline must not
		 * repeat the command */
		KDB_FLAG_CLEAR(CMD_INTERRUPT);
		KDB_STATE_SET(PAGER);
		argc = 0;	/* no repeat */
	}

	if (*cp != '\n' && *cp != '\0') {
		argc = 0;
		cpp = cbuf;
		while (*cp) {
			/* skip whitespace */
			while (isspace(*cp))
				cp++;
			if ((*cp == '\0') || (*cp == '\n') ||
			    (*cp == '#' && !defcmd_in_progress))
				break;
			/* special case: check for | grep pattern */
			if (*cp == '|') {
				check_grep++;
				break;
			}
			if (cpp >= cbuf + CMD_BUFLEN) {
				kdb_printf("kdb_parse: command buffer "
					   "overflow, command ignored\n%s\n",
					   cmdstr);
				return KDB_NOTFOUND;
			}
			if (argc >= MAXARGC - 1) {
				kdb_printf("kdb_parse: too many arguments, "
					   "command ignored\n%s\n", cmdstr);
				return KDB_NOTFOUND;
			}
			argv[argc++] = cpp;
			escaped = 0;
			quoted = '\0';
			/* Copy to next unquoted and unescaped
			 * whitespace or '=' */
			while (*cp && *cp != '\n' &&
			       (escaped || quoted || !isspace(*cp))) {
				if (cpp >= cbuf + CMD_BUFLEN)
					break;
				if (escaped) {
					escaped = 0;
					*cpp++ = *cp++;
					continue;
				}
				if (*cp == '\\') {
					escaped = 1;
					++cp;
					continue;
				}
				if (*cp == quoted)
					quoted = '\0';
				else if (*cp == '\'' || *cp == '"')
					quoted = *cp;
				*cpp = *cp++;
				if (*cpp == '=' && !quoted)
					break;
				++cpp;
			}
			*cpp++ = '\0';	/* Squash a ws or '=' character */
		}
	}
	if (!argc)
		return 0;
	if (check_grep)
		parse_grep(cp);
	if (defcmd_in_progress) {
		int result = kdb_defcmd2(cmdstr, argv[0]);
		if (!defcmd_in_progress) {
			argc = 0;	/* avoid repeat on endefcmd */
			*(argv[0]) = '\0';
		}
		return result;
	}
	if (argv[0][0] == '-' && argv[0][1] &&
	    (argv[0][1] < '0' || argv[0][1] > '9')) {
		ignore_errors = 1;
		++argv[0];
	}

	list_for_each_entry(tp, &kdb_cmds_head, list_node) {
		/*
		 * If this command is allowed to be abbreviated,
		 * check to see if this is it.
		 */
		if (tp->minlen && (strlen(argv[0]) <= tp->minlen) &&
		    (strncmp(argv[0], tp->name, tp->minlen) == 0))
			break;

		if (strcmp(argv[0], tp->name) == 0)
			break;
	}

	/*
	 * If we don't find a command by this name, see if the first
	 * few characters of this match any of the known commands.
	 * e.g., md1c20 should match md.
	 */
	if (list_entry_is_head(tp, &kdb_cmds_head, list_node)) {
		list_for_each_entry(tp, &kdb_cmds_head, list_node) {
			if (strncmp(argv[0], tp->name, strlen(tp->name)) == 0)
				break;
		}
	}

	if (!list_entry_is_head(tp, &kdb_cmds_head, list_node)) {
		int result;

		if (!kdb_check_flags(tp->flags, kdb_cmd_enabled, argc <= 1))
			return KDB_NOPERM;

		KDB_STATE_SET(CMD);
		result = (*tp->func)(argc-1, (const char **)argv);
		if (result && ignore_errors && result > KDB_CMD_GO)
			result = 0;
		KDB_STATE_CLEAR(CMD);

		if (tp->flags & KDB_REPEAT_WITH_ARGS)
			return result;

		argc = tp->flags & KDB_REPEAT_NO_ARGS ? 1 : 0;
		if (argv[argc])
			*(argv[argc]) = '\0';
		return result;
	}

	/*
	 * If the input with which we were presented does not
	 * map to an existing command, attempt to parse it as an
	 * address argument and display the result.   Useful for
	 * obtaining the address of a variable, or the nearest symbol
	 * to an address contained in a register.
	 */
	{
		unsigned long value;
		char *name = NULL;
		long offset;
		int nextarg = 0;

		if (kdbgetaddrarg(0, (const char **)argv, &nextarg,
				  &value, &offset, &name)) {
			return KDB_NOTFOUND;
		}

		kdb_printf("%s = ", argv[0]);
		kdb_symbol_print(value, NULL, KDB_SP_DEFAULT);
		kdb_printf("\n");
		return 0;
	}
}


int __weak kgdb_arch_init(void)
{
	return 0;
}


int kdbgetu64arg(const char *arg, u64 *value)
{
	char *endp;
	u64 val;

	val = simple_strtoull(arg, &endp, 0);

	if (endp == arg) {

		val = simple_strtoull(arg, &endp, 16);
		if (endp == arg)
			return KDB_BADINT;
	}

	*value = val;

	return 0;
}


int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
	      kdb_dbtrap_t db_result, struct pt_regs *regs)
{
	int result = 1;
	/* Stay in kdb() until 'go', 'ss[b]' or an error */
	while (1) {
		/*
		 * All processors except the one that is in control
		 * will spin here.
		 */
		KDB_DEBUG_STATE("kdb_main_loop 1", reason);
		while (KDB_STATE(HOLD_CPU)) {
			/* state KDB is turned off by kdb_cpu to see if the
			 * other cpus are still live, each cpu in this loop
			 * turns it back on.
			 */
			if (!KDB_STATE(KDB))
				KDB_STATE_SET(KDB);
		}

		KDB_STATE_CLEAR(SUPPRESS);
		KDB_DEBUG_STATE("kdb_main_loop 2", reason);
		if (KDB_STATE(LEAVING))
			break;	/* Another cpu said 'go' */
		/* Still using kdb, this processor is in control */
		result = kdb_local(reason2, error, regs, db_result);
		KDB_DEBUG_STATE("kdb_main_loop 3", result);

		if (result == KDB_CMD_CPU)
			break;

		if (result == KDB_CMD_SS) {
			KDB_STATE_SET(DOING_SS);
			break;
		}

		if (result == KDB_CMD_KGDB) {
			if (!KDB_STATE(DOING_KGDB))
				kdb_printf("Entering please attach debugger "
					   "or use $D#44+ or $3#33\n");
			break;
		}
		if (result && result != 1 && result != KDB_CMD_GO)
			kdb_printf("\nUnexpected kdb_local return code %d\n",
				   result);
		KDB_DEBUG_STATE("kdb_main_loop 4", reason);
		break;
	}
	if (KDB_STATE(DOING_SS))
		KDB_STATE_CLEAR(SSBPT);

	/* Clean up any keyboard devices before leaving */
	kdb_kbd_cleanup_state();

	return result;
}


static int kdb_rm(int argc, const char **argv)
{
#if DBG_MAX_REG_NUM > 0
	int diag;
	const char *rname;
	int i;
	u64 reg64;
	u32 reg32;
	u16 reg16;
	u8 reg8;

	if (argc != 2)
		return KDB_ARGCOUNT;
	/*
	 * Allow presence or absence of leading '%' symbol.
	 */
	rname = argv[1];
	if (*rname == '%')
		rname++;

	diag = kdbgetu64arg(argv[2], &reg64);
	if (diag)
		return diag;

	diag = kdb_check_regs();
	if (diag)
		return diag;

	diag = KDB_BADREG;
	for (i = 0; i < DBG_MAX_REG_NUM; i++) {
		if (strcmp(rname, dbg_reg_def[i].name) == 0) {
			diag = 0;
			break;
		}
	}
	if (!diag) {
		switch(dbg_reg_def[i].size * 8) {
		case 8:
			reg8 = reg64;
			dbg_set_reg(i, &reg8, kdb_current_regs);
			break;
		case 16:
			reg16 = reg64;
			dbg_set_reg(i, &reg16, kdb_current_regs);
			break;
		case 32:
			reg32 = reg64;
			dbg_set_reg(i, &reg32, kdb_current_regs);
			break;
		case 64:
			dbg_set_reg(i, &reg64, kdb_current_regs);
			break;
		}
	}
	return diag;
#else
	kdb_printf("ERROR: Register set currently not implemented\n");
    return 0;
#endif
}


int dbg_deactivate_sw_breakpoints(void)
{
	int error;
	int ret = 0;
	int i;

	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
		if (kgdb_break[i].state != BP_ACTIVE)
			continue;
		error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
		if (error) {
			pr_info("BP remove failed: %lx\n",
				kgdb_break[i].bpt_addr);
			ret = error;
		}

		kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
		kgdb_break[i].state = BP_SET;
	}
	return ret;
}


static int kdb_rd(int argc, const char **argv)
{
	int len = kdb_check_regs();
#if DBG_MAX_REG_NUM > 0
	int i;
	char *rname;
	int rsize;
	u64 reg64;
	u32 reg32;
	u16 reg16;
	u8 reg8;

	if (len)
		return len;

	for (i = 0; i < DBG_MAX_REG_NUM; i++) {
		rsize = dbg_reg_def[i].size * 2;
		if (rsize > 16)
			rsize = 2;
		if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
			len = 0;
			kdb_printf("\n");
		}
		if (len)
			len += kdb_printf("  ");
		switch(dbg_reg_def[i].size * 8) {
		case 8:
			rname = dbg_get_reg(i, &reg8, kdb_current_regs);
			if (!rname)
				break;
			len += kdb_printf("%s: %02x", rname, reg8);
			break;
		case 16:
			rname = dbg_get_reg(i, &reg16, kdb_current_regs);
			if (!rname)
				break;
			len += kdb_printf("%s: %04x", rname, reg16);
			break;
		case 32:
			rname = dbg_get_reg(i, &reg32, kdb_current_regs);
			if (!rname)
				break;
			len += kdb_printf("%s: %08x", rname, reg32);
			break;
		case 64:
			rname = dbg_get_reg(i, &reg64, kdb_current_regs);
			if (!rname)
				break;
			len += kdb_printf("%s: %016llx", rname, reg64);
			break;
		default:
			len += kdb_printf("%s: ??", dbg_reg_def[i].name);
		}
	}
	kdb_printf("\n");
#else
	if (len)
		return len;

	kdb_dumpregs(kdb_current_regs);
#endif
	return 0;
}


static void kdb_sysinfo(struct sysinfo *val)
{
	u64 uptime = ktime_get_mono_fast_ns();

	memset(val, 0, sizeof(*val));
	val->uptime = div_u64(uptime, NSEC_PER_SEC);
	val->loads[0] = avenrun[0];
	val->loads[1] = avenrun[1];
	val->loads[2] = avenrun[2];
	val->procs = nr_threads-1;
	si_meminfo(val);

	return;
}


static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
{
	if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
		return -EINVAL;
	arch_kgdb_ops.enable_nmi(1);
	return 0;
}


int __weak kgdb_validate_break_address(unsigned long addr)
{
	struct kgdb_bkpt tmp;
	int err;

	if (kgdb_within_blocklist(addr))
		return -EINVAL;

	/* Validate setting the breakpoint and then removing it.  If the
	 * remove fails, the kernel needs to emit a bad message because we
	 * are deep trouble not being able to put things back the way we
	 * found them.
	 */
	tmp.bpt_addr = addr;
	err = kgdb_arch_set_breakpoint(&tmp);
	if (err)
		return err;
	err = kgdb_arch_remove_breakpoint(&tmp);
	if (err)
		pr_err("Critical breakpoint error, kernel memory destroyed at: %lx\n",
		       addr);
	return err;
}


static int kdb_help(int argc, const char **argv)
{
	kdbtab_t *kt;

	kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description");
	kdb_printf("-----------------------------"
		   "-----------------------------\n");
	list_for_each_entry(kt, &kdb_cmds_head, list_node) {
		char *space = "";
		if (KDB_FLAG(CMD_INTERRUPT))
			return 0;
		if (!kdb_check_flags(kt->flags, kdb_cmd_enabled, true))
			continue;
		if (strlen(kt->usage) > 20)
			space = "\n                                    ";
		kdb_printf("%-15.15s %-20s%s%s\n", kt->name,
			   kt->usage, space, kt->help);
	}
	return 0;
}


void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
{
	BUG_ON(kgdb_connected);

	/*
	 * KGDB is no longer able to communicate out, so
	 * unregister our callbacks and reset state.
	 */
	kgdb_unregister_callbacks();

	spin_lock(&kgdb_registration_lock);

	WARN_ON_ONCE(dbg_io_ops != old_dbg_io_ops);
	dbg_io_ops = NULL;

	spin_unlock(&kgdb_registration_lock);

	if (old_dbg_io_ops->deinit)
		old_dbg_io_ops->deinit();

	pr_info("Unregistered I/O driver %s, debugger disabled\n",
		old_dbg_io_ops->name);
}


static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
		     kdb_dbtrap_t db_result)
{
	char *cmdbuf;
	int diag;
	struct task_struct *kdb_current =
		kdb_curr_task(raw_smp_processor_id());

	KDB_DEBUG_STATE("kdb_local 1", reason);

	kdb_check_for_lockdown();

	kdb_go_count = 0;
	if (reason == KDB_REASON_DEBUG) {
		/* special case below */
	} else {
		kdb_printf("\nEntering kdb (current=0x%px, pid %d) ",
			   kdb_current, kdb_current ? kdb_current->pid : 0);
#if defined(CONFIG_SMP)
		kdb_printf("on processor %d ", raw_smp_processor_id());
#endif
	}

	switch (reason) {
	case KDB_REASON_DEBUG:
	{
		/*
		 * If re-entering kdb after a single step
		 * command, don't print the message.
		 */
		switch (db_result) {
		case KDB_DB_BPT:
			kdb_printf("\nEntering kdb (0x%px, pid %d) ",
				   kdb_current, kdb_current->pid);
#if defined(CONFIG_SMP)
			kdb_printf("on processor %d ", raw_smp_processor_id());
#endif
			kdb_printf("due to Debug @ " kdb_machreg_fmt "\n",
				   instruction_pointer(regs));
			break;
		case KDB_DB_SS:
			break;
		case KDB_DB_SSBPT:
			KDB_DEBUG_STATE("kdb_local 4", reason);
			return 1;	/* kdba_db_trap did the work */
		default:
			kdb_printf("kdb: Bad result from kdba_db_trap: %d\n",
				   db_result);
			break;
		}

	}
		break;
	case KDB_REASON_ENTER:
		if (KDB_STATE(KEYBOARD))
			kdb_printf("due to Keyboard Entry\n");
		else
			kdb_printf("due to KDB_ENTER()\n");
		break;
	case KDB_REASON_KEYBOARD:
		KDB_STATE_SET(KEYBOARD);
		kdb_printf("due to Keyboard Entry\n");
		break;
	case KDB_REASON_ENTER_SLAVE:
		/* drop through, slaves only get released via cpu switch */
	case KDB_REASON_SWITCH:
		kdb_printf("due to cpu switch\n");
		break;
	case KDB_REASON_OOPS:
		kdb_printf("Oops: %s\n", kdb_diemsg);
		kdb_printf("due to oops @ " kdb_machreg_fmt "\n",
			   instruction_pointer(regs));
		kdb_dumpregs(regs);
		break;
	case KDB_REASON_SYSTEM_NMI:
		kdb_printf("due to System NonMaskable Interrupt\n");
		break;
	case KDB_REASON_NMI:
		kdb_printf("due to NonMaskable Interrupt @ "
			   kdb_machreg_fmt "\n",
			   instruction_pointer(regs));
		break;
	case KDB_REASON_SSTEP:
	case KDB_REASON_BREAK:
		kdb_printf("due to %s @ " kdb_machreg_fmt "\n",
			   reason == KDB_REASON_BREAK ?
			   "Breakpoint" : "SS trap", instruction_pointer(regs));
		/*
		 * Determine if this breakpoint is one that we
		 * are interested in.
		 */
		if (db_result != KDB_DB_BPT) {
			kdb_printf("kdb: error return from kdba_bp_trap: %d\n",
				   db_result);
			KDB_DEBUG_STATE("kdb_local 6", reason);
			return 0;	/* Not for us, dismiss it */
		}
		break;
	case KDB_REASON_RECURSE:
		kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n",
			   instruction_pointer(regs));
		break;
	default:
		kdb_printf("kdb: unexpected reason code: %d\n", reason);
		KDB_DEBUG_STATE("kdb_local 8", reason);
		return 0;	/* Not for us, dismiss it */
	}

	while (1) {
		/*
		 * Initialize pager context.
		 */
		kdb_nextline = 1;
		KDB_STATE_CLEAR(SUPPRESS);
		kdb_grepping_flag = 0;
		/* ensure the old search does not leak into '/' commands */
		kdb_grep_string[0] = '\0';

		cmdbuf = cmd_cur;
		*cmdbuf = '\0';
		*(cmd_hist[cmd_head]) = '\0';

do_full_getstr:
		/* PROMPT can only be set if we have MEM_READ permission. */
		snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
			 raw_smp_processor_id());
		if (defcmd_in_progress)
			strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN);

		/*
		 * Fetch command from keyboard
		 */
		cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str);
		if (*cmdbuf != '\n') {
			if (*cmdbuf < 32) {
				if (cmdptr == cmd_head) {
					strscpy(cmd_hist[cmd_head], cmd_cur,
						CMD_BUFLEN);
					*(cmd_hist[cmd_head] +
					  strlen(cmd_hist[cmd_head])-1) = '\0';
				}
				if (!handle_ctrl_cmd(cmdbuf))
					*(cmd_cur+strlen(cmd_cur)-1) = '\0';
				cmdbuf = cmd_cur;
				goto do_full_getstr;
			} else {
				strscpy(cmd_hist[cmd_head], cmd_cur,
					CMD_BUFLEN);
			}

			cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT;
			if (cmd_head == cmd_tail)
				cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT;
		}

		cmdptr = cmd_head;
		diag = kdb_parse(cmdbuf);
		if (diag == KDB_NOTFOUND) {
			drop_newline(cmdbuf);
			kdb_printf("Unknown kdb command: '%s'\n", cmdbuf);
			diag = 0;
		}
		if (diag == KDB_CMD_GO
		 || diag == KDB_CMD_CPU
		 || diag == KDB_CMD_SS
		 || diag == KDB_CMD_KGDB)
			break;

		if (diag)
			kdb_cmderror(diag);
	}
	KDB_DEBUG_STATE("kdb_local 9", diag);
	return diag;
}


int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
{
	struct nfc_se *se;
	int rc;

	pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx);

	device_lock(&dev->dev);

	if (dev->shutting_down) {
		rc = -ENODEV;
		goto error;
	}

	if (!dev->dev_up) {
		rc = -ENODEV;
		goto error;
	}

	if (dev->polling) {
		rc = -EBUSY;
		goto error;
	}

	if (!dev->ops->enable_se || !dev->ops->disable_se) {
		rc = -EOPNOTSUPP;
		goto error;
	}

	se = nfc_find_se(dev, se_idx);
	if (!se) {
		rc = -EINVAL;
		goto error;
	}

	if (se->state == NFC_SE_ENABLED) {
		rc = -EALREADY;
		goto error;
	}

	rc = dev->ops->enable_se(dev, se_idx);
	if (rc >= 0)
		se->state = NFC_SE_ENABLED;

error:
	device_unlock(&dev->dev);
	return rc;
}


int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
{
	int rc = 0;

	pr_debug("%s do firmware %s\n", dev_name(&dev->dev), firmware_name);

	device_lock(&dev->dev);

	if (dev->shutting_down) {
		rc = -ENODEV;
		goto error;
	}

	if (dev->dev_up) {
		rc = -EBUSY;
		goto error;
	}

	if (!dev->ops->fw_download) {
		rc = -EOPNOTSUPP;
		goto error;
	}

	dev->fw_download_in_progress = true;
	rc = dev->ops->fw_download(dev, firmware_name);
	if (rc)
		dev->fw_download_in_progress = false;

error:
	device_unlock(&dev->dev);
	return rc;
}


static struct sw_flow_actions *nla_alloc_flow_actions(int size)
{
	struct sw_flow_actions *sfa;

	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);

	sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
	if (!sfa)
		return ERR_PTR(-ENOMEM);

	sfa->actions_len = 0;
	return sfa;
}


static int parse_vlan_from_nlattrs(struct sw_flow_match *match,
				   u64 *key_attrs, const struct nlattr **a,
				   bool is_mask, bool log)
{
	int err;
	bool encap_valid = false;

	err = __parse_vlan_from_nlattrs(match, key_attrs, false, a,
					is_mask, log);
	if (err)
		return err;

	encap_valid = !!(match->key->eth.vlan.tci & htons(VLAN_CFI_MASK));
	if (encap_valid) {
		err = __parse_vlan_from_nlattrs(match, key_attrs, true, a,
						is_mask, log);
		if (err)
			return err;
	}

	return 0;
}


static void ovs_nla_free_dec_ttl_action(const struct nlattr *action)
{
	const struct nlattr *a = nla_data(action);

	switch (nla_type(a)) {
	case OVS_DEC_TTL_ATTR_ACTION:
		ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
		break;
	}
}


static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)
{
	const struct nlattr *a;
	int rem;

	/* Whenever new actions are added, the need to update this
	 * function should be considered.
	 */
	BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 23);

	if (!actions)
		return;

	nla_for_each_attr(a, actions, len, rem) {
		switch (nla_type(a)) {
		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
			ovs_nla_free_check_pkt_len_action(a);
			break;

		case OVS_ACTION_ATTR_CLONE:
			ovs_nla_free_clone_action(a);
			break;

		case OVS_ACTION_ATTR_CT:
			ovs_ct_free_action(a);
			break;

		case OVS_ACTION_ATTR_DEC_TTL:
			ovs_nla_free_dec_ttl_action(a);
			break;

		case OVS_ACTION_ATTR_SAMPLE:
			ovs_nla_free_sample_action(a);
			break;

		case OVS_ACTION_ATTR_SET:
			ovs_nla_free_set_action(a);
			break;
		}
	}
}


static int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
			     struct sk_buff *skb)
{
	struct nlattr *start;

	start = nla_nest_start_noflag(skb, OVS_KEY_ATTR_NSH);
	if (!start)
		return -EMSGSIZE;

	if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base))
		goto nla_put_failure;

	if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) {
		if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1,
			    sizeof(nsh->context), nsh->context))
			goto nla_put_failure;
	}

	/* Don't support MD type 2 yet */

	nla_nest_end(skb, start);

	return 0;

nla_put_failure:
	return -EMSGSIZE;
}


int ovs_nla_put_tunnel_info(struct sk_buff *skb,
			    struct ip_tunnel_info *tun_info)
{
	return __ip_tun_to_nlattr(skb, &tun_info->key,
				  ip_tunnel_info_opts(tun_info),
				  tun_info->options_len,
				  ip_tunnel_info_af(tun_info), tun_info->mode);
}