Пример #1
0
/*
 * Validate and scale a margin value.
 */
static double
parse_margin(char *s, const char *what)
{
    double d;
    char *nextp;

    d = strtod(s, &nextp);
    if (d > 0.0) {
	while (*nextp == ' ') {
	    nextp++;
	}
	if (*nextp == '\0' || *nextp == '"' ||
		!strcasecmp(nextp, "in") ||
		!strcasecmp(nextp, "inch") ||
		!strcasecmp(nextp, "inches")) {
	    /* Do nothing. */
	} else if (!strcasecmp(nextp, "mm")) {
	    d /= 25.4;
	} else if (!strcasecmp(nextp, "cm")) {
	    d /= 2.54;
	} else {
	    vtrace("gdi: unknown %s unit '%s'\n",
		    what, nextp);
	}
    } else {
	vtrace("gdi: invalid %s '%s'\n", what, s);
	return 0;
    }
    return d;
}
Пример #2
0
/*
 * log_mark --
 *	Log a mark position.  For the log to work, we assume that there
 *	aren't any operations that just put out a log record -- this
 *	would mean that undo operations would only reset marks, and not
 *	cause any other change.
 *
 * PUBLIC: int log_mark __P((SCR *, LMARK *));
 */
int
log_mark(SCR *sp, LMARK *lmp)
{
	DBT data, key;
	EXF *ep;

	ep = sp->ep;
	if (F_ISSET(ep, F_NOLOG))
		return (0);

	/* Put out one initial cursor record per set of changes. */
	if (ep->l_cursor.lno != OOBLNO) {
		if (log_cursor1(sp, LOG_CURSOR_INIT))
			return (1);
		ep->l_cursor.lno = OOBLNO;
		ep->l_win = sp->wp;
	}

	if ((sp->db_error = 
		__vi_mark_log(ep->env, NULL, &ep->lsn_cur, 0, 
			    lmp)) != 0) {
		msgq(sp, M_DBERR, "cursor_log");
		return 1;
	}

#if defined(DEBUG) && 0
	vtrace(sp, "%lu: mark %c: %lu/%u\n",
	    ep->l_cur, lmp->name, lmp->lno, lmp->cno);
#endif
	/* Reset high water mark. */
	ep->l_high = ++ep->l_cur;
	return (0);
}
Пример #3
0
void Tableau::trace(int flag, _In_z_ _Printf_format_string_ TCHAR const * const format, ...) const {
  if(isTracing(flag)) {
    va_list argptr;
    va_start(argptr,format);
    vtrace(format,argptr);
    va_end(argptr);
  }
}
Пример #4
0
/*
 * Create a Roman font.
 * Returns 0 for success, -1 for failure.
 */
static int
create_roman_font(HDC dc, int fheight, int fwidth, const char **fail)
{
    char *w, *h;

    w = fwidth? xs_buffer("%d", fwidth): NewString("(auto)");
    h = fheight? xs_buffer("%d", fheight): NewString("(auto)");
    vtrace("[gdi] requesting a font %sx%s logical units\n", w, h);
    Free(w);
    Free(h);

    pstate.font = CreateFont(
	    fheight,		/* height */
	    fwidth,		/* width */
	    0,			/* escapement */
	    0,			/* orientation */
	    FW_NORMAL,		/* weight */
	    FALSE,		/* italic */
	    FALSE,		/* underline */
	    FALSE,		/* strikeout */
	    DEFAULT_CHARSET,	/* character set */
	    OUT_OUTLINE_PRECIS,	/* output precision */
	    CLIP_DEFAULT_PRECIS,/* clip precision */
	    DEFAULT_QUALITY,	/* quality */
	    FIXED_PITCH|FF_DONTCARE,/* pitch and family */
	    uparm.font_name);	/* face */
    if (pstate.font == NULL) {
	*fail = "CreateFont failed";
	return -1;
    }

    /* Measure a space to find out the size we got. */
    SelectObject(dc, pstate.font);
    if (!GetTextExtentPoint32(dc, " ", 1, &pstate.space_size)) {
	*fail = "GetTextExtentPoint32 failed";
	return -1;
    }
    vtrace("[gdi] space character is %dx%d logical units\n",
	    (int)pstate.space_size.cx, (int)pstate.space_size.cy);
    pstate.usable_cols = pstate.usable_xpixels / pstate.space_size.cx;
    pstate.usable_rows = pstate.usable_ypixels / pstate.space_size.cy;
    vtrace("[gdi] usable area is %dx%d characters\n",
	    pstate.usable_cols, pstate.usable_rows);
    return 0;
}
Пример #5
0
/*
 * db_insert --
 *	Insert a line into the file.
 *
 * PUBLIC: int db_insert __P((SCR *, db_recno_t, CHAR_T *, size_t));
 */
int
db_insert(SCR *sp, db_recno_t lno, CHAR_T *p, size_t len)
{
#if defined(DEBUG) && 0
	vtrace(sp, "insert before %lu: len %lu {%.*s}\n",
	    (u_long)lno, (u_long)len, MIN(len, 20), p);
#endif
	return append(sp, lno - 1, p, len, LINE_INSERT, 1);
}
Пример #6
0
/*
 * db_append --
 *	Append a line into the file.
 *
 * PUBLIC: int db_append __P((SCR *, int, db_recno_t, CHAR_T *, size_t));
 */
int
db_append(SCR *sp, int update, db_recno_t lno, const CHAR_T *p, size_t len)
{
#if defined(DEBUG) && 0
	vtrace(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
#endif
		
	/* Update file. */
	return append(sp, lno, p, len, LINE_APPEND, update);
}
Пример #7
0
/**
 * Send output on an http session.
 *
 * @param[in] mhandle	our handle
 * @param[in] buf	buffer to transmit
 * @param[in] len	length of buffer
 */
void
hio_send(void *mhandle, const char *buf, size_t len)
{
    session_t *s = mhandle;
    ssize_t nw;

    nw = send(s->s, buf, (int)len, 0);
    if (nw < 0) {
	vtrace("http send error: %s\n", socket_errtext());
    }
}
Пример #8
0
/*
 * db_set --
 *	Store a line in the file.
 *
 * PUBLIC: int db_set __P((SCR *, db_recno_t, CHAR_T *, size_t));
 */
int
db_set(SCR *sp, db_recno_t lno, CHAR_T *p, size_t len)
{
	DBT data, key;
	EXF *ep;
	const char *fp;
	size_t flen;

#if defined(DEBUG) && 0
	vtrace(sp, "replace line %lu: len %lu {%.*s}\n",
	    (u_long)lno, (u_long)len, MIN(len, 20), p);
#endif
	/* Check for no underlying file. */
	if ((ep = sp->ep) == NULL) {
		ex_emsg(sp, NULL, EXM_NOFILEYET);
		return (1);
	}
	if (ep->l_win && ep->l_win != sp->wp) {
		ex_emsg(sp, NULL, EXM_LOCKED);
		return 1;
	}
		
	/* Log before change. */
	log_line(sp, lno, LOG_LINE_RESET_B);

	INT2FILE(sp, p, len, fp, flen);

	/* Update file. */
	memset(&key, 0, sizeof(key));
	key.data = &lno;
	key.size = sizeof(lno);
	memset(&data, 0, sizeof(data));
	data.data = __UNCONST(fp);
	data.size = flen;
	if ((sp->db_error = ep->db->put(ep->db, NULL, &key, &data, 0)) != 0) {
		msgq(sp, M_DBERR, "006|unable to store line %lu", (u_long)lno);
		return (1);
	}

	/* Flush the cache, update line count, before screen update. */
	update_cache(sp, LINE_RESET, lno);

	/* File now dirty. */
	if (F_ISSET(ep, F_FIRSTMODIFY))
		(void)rcv_init(sp);
	F_SET(ep, F_MODIFIED);

	/* Log after change. */
	log_line(sp, lno, LOG_LINE_RESET_F);

	/* Update screen. */
	return (scr_update(sp, lno, LINE_RESET, 1));
}
Пример #9
0
/*
 * db_delete --
 *	Delete a line from the file.
 *
 * PUBLIC: int db_delete __P((SCR *, db_recno_t));
 */
int
db_delete(SCR *sp, db_recno_t lno)
{
	DBT key;
	EXF *ep;

#if defined(DEBUG) && 0
	vtrace(sp, "delete line %lu\n", (u_long)lno);
#endif
	/* Check for no underlying file. */
	if ((ep = sp->ep) == NULL) {
		ex_emsg(sp, NULL, EXM_NOFILEYET);
		return (1);
	}
	if (ep->l_win && ep->l_win != sp->wp) {
		ex_emsg(sp, NULL, EXM_LOCKED);
		return 1;
	}
		
	/* Update marks, @ and global commands. */
	if (line_insdel(sp, LINE_DELETE, lno))
		return 1;

	/* Log before change. */
	log_line(sp, lno, LOG_LINE_DELETE_B);

	/* Update file. */
	memset(&key, 0, sizeof(key));
	key.data = &lno;
	key.size = sizeof(lno);
	if ((sp->db_error = ep->db->del(ep->db, NULL, &key, 0)) != 0) {
		msgq(sp, M_DBERR, "003|unable to delete line %lu", 
		    (u_long)lno);
		return (1);
	}

	/* Flush the cache, update line count, before screen update. */
	update_cache(sp, LINE_DELETE, lno);

	/* File now modified. */
	if (F_ISSET(ep, F_FIRSTMODIFY))
		(void)rcv_init(sp);
	F_SET(ep, F_MODIFIED);

	/* Log after change. */
	log_line(sp, lno, LOG_LINE_DELETE_F);

	/* Update screen. */
	return (scr_update(sp, lno, LINE_DELETE, 1));
}
Пример #10
0
/*
 * Initialize printing to a GDI printer.
 */
gdi_status_t
gdi_print_start(const char *printer_name, unsigned opts)
{
    const char *fail = "";

    if (!uparm.done) {
	/* Set the defaults. */
	uparm.orientation = 0;
	uparm.hmargin = 0.5;
	uparm.vmargin = 0.5;
	uparm.font_name = NULL;
	uparm.font_size = 0; /* auto */
	uparm.spp = 1;

	/* Gather up the parameters. */
	gdi_get_params(&uparm);

	/* Don't do this again. */
	uparm.done = true;
    }

    /* Initialize the printer and pop up the dialog. */
    switch (gdi_init(printer_name, opts, &fail)) {
    case GDI_STATUS_SUCCESS:
	vtrace("[gdi] initialized\n");
	break;
    case GDI_STATUS_ERROR:
	popup_an_error("Printer initialization error: %s", fail);
	return GDI_STATUS_ERROR;
    case GDI_STATUS_CANCEL:
	vtrace("[gdi] canceled\n");
	return GDI_STATUS_CANCEL;
    }

    return GDI_STATUS_SUCCESS;
}
Пример #11
0
/*
 * log_cursor1 --
 *	Actually push a cursor record out.
 */
static int
log_cursor1(SCR *sp, int type)
{
	DBT data, key;
	EXF *ep;

	ep = sp->ep;

	/*
	if (type == LOG_CURSOR_INIT &&
	    LOCK_TRY(sp->wp, ep))
		return 1;
	*/

	if (type == LOG_CURSOR_INIT && 
	    (sp->db_error = __vi_log_truncate(ep)) != 0) {
		msgq(sp, M_DBERR, "truncate");
		return 1;
	}
	if ((sp->db_error = 
		__vi_cursor_log(ep->env, NULL, &ep->lsn_cur, 0, type, 
			    ep->l_cursor.lno, ep->l_cursor.cno)) != 0) {
		msgq(sp, M_DBERR, "cursor_log");
		return 1;
	}
	if (type == LOG_CURSOR_END) {
		MEMCPY(&ep->lsn_high, &ep->lsn_cur, 1);
		/* XXXX should not be needed */
		ep->env->log_flush(ep->env, NULL);
	}

#if defined(DEBUG) && 0
	vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
	    type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
	    sp->lno, sp->cno);
#endif
	/* Reset high water mark. */
	ep->l_high = ++ep->l_cur;

	/*
	if (type == LOG_CURSOR_END)
		LOCK_UNLOCK(sp->wp, ep);
	*/
	return (0);
}
Пример #12
0
/**
 * httpd timeout.
 *
 * @param[in] id	timeout ID
 */
static void
hio_timeout(ioid_t id)
{
    session_t *session;

    session = NULL;
    FOREACH_LLIST(&sessions, session, session_t *) {
	if (session->toid == id) {
	    break;
	}
    } FOREACH_LLIST_END(&sessions, session, session_t *);
    if (session == NULL) {
	vtrace("httpd mystery timeout\n");
	return;
    }

    session->toid = NULL_IOID;
    httpd_close(session->dhandle, "timeout");
    hio_socket_close(session);
}
Пример #13
0
/* Pop up an error dialog. */
void
popup_an_error(const char *fmt, ...)
{
    va_list args;
    char *s;

    va_start(args, fmt);
    s = xs_vbuffer(fmt, args);
    va_end(args);

    /* Log to the trace file. */
    vtrace("%s\n", s);

    if (sms_redirect()) {
	sms_error(s);
    } else {
	screen_suspend();
	(void) fprintf(stderr, "%s\n", s);
	fflush(stderr);
	any_error_output = true;
	macro_output = true;
    }
    Free(s);
}
Пример #14
0
/**
 * New inbound connection for httpd.
 *
 * @param[in] fd	socket file descriptor
 * @param[in] id	I/O ID
 */
void
hio_connection(iosrc_t fd, ioid_t id)
{
    socket_t t;
    union {
	struct sockaddr sa;
	struct sockaddr_in sin;
#if defined(X3270_IPV6) /*[*/
	struct sockaddr_in6 sin6;
#endif /*]*/
    } sa;
    socklen_t len;
    char hostbuf[128];
    session_t *session;

    len = sizeof(sa);
    t = accept(listen_s, &sa.sa, &len);
    if (t == INVALID_SOCKET) {
	vtrace("httpd accept error: %s%s\n", socket_errtext(),
		(socket_errno() == SE_EWOULDBLOCK)? " (harmless)": "");
	return;
    }
    if (n_sessions >= N_SESSIONS) {
	vtrace("Too many connections.\n");
	SOCK_CLOSE(t);
	return;
    }

    session = Malloc(sizeof(session_t));
    memset(session, 0, sizeof(session_t));
    vb_init(&session->pending.result);
    session->s = t;
#if defined(_WIN32) /*[*/
    session->event = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (session->event == NULL) {
	vtrace("httpd: can't create socket handle\n");
	SOCK_CLOSE(t);
	Free(session);
	return;
    }
    if (WSAEventSelect(session->s, session->event, FD_READ | FD_CLOSE) != 0) {
	vtrace("httpd: Can't set socket handle events\n");
	CloseHandle(session->event);
	SOCK_CLOSE(t);
	Free(session);
	return;
    }
#endif /*]*/
    if (sa.sa.sa_family == AF_INET) {
	session->dhandle = httpd_new(session,
		lazyaf("%s:%u",
		    inet_ntop(AF_INET, &sa.sin.sin_addr, hostbuf,
			sizeof(hostbuf)),
		    ntohs(sa.sin.sin_port)));
    }
#if defined(X3270_IPV6) /*[*/
    else if (sa.sa.sa_family == AF_INET6) {
	session->dhandle = httpd_new(session,
		lazyaf("%s:%u",
		    inet_ntop(AF_INET6, &sa.sin6.sin6_addr, hostbuf,
			sizeof(hostbuf)),
		    ntohs(sa.sin6.sin6_port)));
    }
#endif /*]*/
    else {
	session->dhandle = httpd_new(session, "???");
    }
#if !defined(_WIN32) /*[*/
    session->ioid = AddInput(t, hio_socket_input);
#else /*][*/
    session->ioid = AddInput(session->event, hio_socket_input);
#endif /*]*/

    /* Set the timeout for the first line of input. */
    session->toid = AddTimeOut(IDLE_MAX * 1000, hio_timeout);

    llist_insert_before(&session->link, sessions.next);
    n_sessions++;
}
Пример #15
0
/**
 * New inbound data for an httpd connection.
 *
 * @param[in] fd	socket file descriptor
 * @param[in] id	I/O ID
 */
void
hio_socket_input(iosrc_t fd, ioid_t id)
{
    session_t *session;
    char buf[1024];
    ssize_t nr;

    session = NULL;
    FOREACH_LLIST(&sessions, session, session_t *) {
	if (session->ioid == id) {
	    break;
	}
    } FOREACH_LLIST_END(&sessions, session, session_t *);
    if (session == NULL) {
	vtrace("httpd mystery input\n");
	return;
    }

    /* Move this session to the front of the list. */
    llist_unlink(&session->link);
    llist_insert_before(&session->link, sessions.next);

    session->idle = 0;

    if (session->toid != NULL_IOID) {
	RemoveTimeOut(session->toid);
	session->toid = NULL_IOID;
    }

    nr = recv(session->s, buf, sizeof(buf), 0);
    if (nr <= 0) {
	const char *ebuf;
	bool harmless = false;

	if (nr < 0) {
	    if (socket_errno() == SE_EWOULDBLOCK) {
		harmless = true;
	    }
	    ebuf = lazyaf("recv error: %s", socket_errtext());
	    vtrace("httpd %s%s\n", ebuf, harmless? " (harmless)": "");
	} else {
	    ebuf = "session EOF";
	}
	if (!harmless) {
	    httpd_close(session->dhandle, ebuf);
	    hio_socket_close(session);
	}
    } else {
	httpd_status_t rv;

	rv = httpd_input(session->dhandle, buf, nr);
	if (rv < 0) {
	    httpd_close(session->dhandle, "protocol error");
	    hio_socket_close(session);
	} else if (rv == HS_PENDING) {
	    /* Stop input on this socket. */
	    RemoveInput(session->ioid);
	    session->ioid = NULL_IOID;
	} else if (session->toid == NULL_IOID) {
	    /* Leave input enabled and start the timeout. */
	    session->toid = AddTimeOut(IDLE_MAX * 1000, hio_timeout);
	}
    }
}
Пример #16
0
void Tableau::trace(_In_z_ _Printf_format_string_ TCHAR const * const format,...) const {
  va_list argptr;
  va_start(argptr,format);
  vtrace(format,argptr);
  va_end(argptr);
}
Пример #17
0
/*
 * Print one screeful to the GDI printer.
 */
static int
gdi_screenful(struct ea *ea, unsigned short rows, unsigned short cols,
	const char **fail)
{
    HDC dc = pstate.dlg.hDC;
    LPDEVMODE devmode;
    int row, col, baddr;
    int rc = 0;
    int status;
    int fa_addr = find_field_attribute_ea(0, ea);
    unsigned char fa = ea[fa_addr].fa;
    bool fa_high, high;
    bool fa_underline, underline;
    bool fa_reverse, reverse;
    unsigned long uc;
    bool is_dbcs;
    char c;
    int usable_rows;
    HFONT got_font = NULL, want_font;
#if defined(GDI_DEBUG) /*[*/
    const char *want_font_name;
#endif /*]*/
    enum { COLOR_NONE, COLOR_NORMAL, COLOR_REVERSE } got_color = COLOR_NONE,
	want_color;

    devmode = (LPDEVMODE)GlobalLock(pstate.dlg.hDevMode);

    /* Compute the usable rows, including the caption. */
    usable_rows = pstate.usable_rows;
    if (pstate.caption) {
	usable_rows -= 2;
    }

    /*
     * Does this screen fit?
     * (Note that the first test, "pstate.out_row", is there so that if the
     * font is so big the image won't fit at all, we still print as much
     * of it as we can.)
     */
    if (pstate.out_row && pstate.out_row + ROWS > usable_rows) {
	if (EndPage(dc) <= 0) {
	    *fail = "EndPage failed";
	    rc = -1;
	    goto done;
	}
	pstate.out_row = 0;
	pstate.screens = 0;
    }

    /* If there is a caption, put it on the last line. */
    if (pstate.out_row == 0 && pstate.caption != NULL) {
	SelectObject(dc, pstate.caption_font);
	status = ExtTextOut(dc,
		pstate.hmargin_pixels - pchar.poffX,
		pstate.vmargin_pixels +
		    ((pstate.usable_rows - 1) * pstate.space_size.cy) -
		    pchar.poffY,
		0, NULL,
		pstate.caption, (UINT)strlen(pstate.caption), NULL);
	if (status <= 0) {
	    *fail = "ExtTextOut failed";
	    rc = -1;
	    goto done;
	}
    }

    /* Draw a line separating the screens. */
    if (pstate.out_row) {
	HPEN pen;

	pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
	SelectObject(dc, pen);
	status = MoveToEx(dc, 
		pstate.hmargin_pixels - pchar.poffX,
		pstate.vmargin_pixels +
		    (pstate.out_row * pstate.space_size.cy) +
		    (pstate.space_size.cy / 2) - pchar.poffY,
		    NULL);
	if (status == 0) {
	    *fail = "MoveToEx failed";
	    rc = -1;
	    goto done;
	}
	status = LineTo(dc,
		pstate.hmargin_pixels - pchar.poffX + pstate.usable_xpixels,
		pstate.vmargin_pixels +
		    (pstate.out_row * pstate.space_size.cy) +
		    (pstate.space_size.cy / 2) - pchar.poffY);
	if (status == 0) {
	    *fail = "LineTo failed";
	    rc = -1;
	    goto done;
	}
	DeleteObject(pen);
    }

    /* Now dump out a screen's worth. */
    if (ea[fa_addr].gr & GR_INTENSIFY) {
	fa_high = true;
    } else {
	fa_high = FA_IS_HIGH(fa);
    }
    fa_reverse = ((ea[fa_addr].gr & GR_REVERSE) != 0);
    fa_underline = ((ea[fa_addr].gr & GR_UNDERLINE) != 0);

    for (baddr = 0, row = 0; row < ROWS; row++) {
	if (pstate.out_row + row >= usable_rows) {
	    break;
	}
	for (col = 0; col < COLS; col++, baddr++) {
	    if (ea[baddr].fa) {
		fa = ea[baddr].fa;
		if (ea[baddr].gr & GR_INTENSIFY) {
		    fa_high = true;
		} else {
		    fa_high = FA_IS_HIGH(fa);
		}
		fa_reverse = ((ea[fa_addr].gr & GR_REVERSE) != 0);
		fa_underline = ((ea[fa_addr].gr & GR_UNDERLINE) != 0);

		/* Just skip it. */
		continue;
	    }
	    if (col >= pstate.usable_cols) {
		continue;
	    }
	    is_dbcs = FALSE;
	    if (FA_IS_ZERO(fa)) {
		if (ctlr_dbcs_state_ea(baddr, ea) == DBCS_LEFT) {
		    uc = 0x3000;
		} else {
		    uc = ' ';
		}
	    } else {
		/* Convert EBCDIC to Unicode. */
		switch (ctlr_dbcs_state(baddr)) {
		case DBCS_NONE:
		case DBCS_SB:
		    uc = ebcdic_to_unicode(ea[baddr].cc, ea[baddr].cs,
			    EUO_NONE);
		    if (uc == 0) {
			uc = ' ';
		    }
		    break;
		case DBCS_LEFT:
		    is_dbcs = TRUE;
		    uc = ebcdic_to_unicode((ea[baddr].cc << 8) |
				ea[baddr + 1].cc,
			    CS_BASE, EUO_NONE);
		    if (uc == 0) {
			uc = 0x3000;
		    }
		    break;
		case DBCS_RIGHT:
		    /* skip altogether, we took care of it above */
		    continue;
		default:
		    uc = ' ';
		    break;
		}
	    }

	    /* Figure out the attributes of the current buffer position. */
	    high = ((ea[baddr].gr & GR_INTENSIFY) != 0);
	    if (!high) {
		high = fa_high;
	    }
	    reverse = ((ea[fa_addr].gr & GR_REVERSE) != 0);
	    if (!reverse) {
		reverse = fa_reverse;
	    }
	    underline = ((ea[fa_addr].gr & GR_UNDERLINE) != 0);
	    if (!underline) {
		underline = fa_underline;
	    }

	    /* Set the bg/fg color and font. */
	    if (reverse) {
		want_color = COLOR_REVERSE;
	    } else {
		want_color = COLOR_NORMAL;
	    }
	    if (want_color != got_color) {
		switch (want_color) {
		case COLOR_REVERSE:
		    SetTextColor(dc, 0xffffff);
		    SetBkColor(dc, 0);
		    SetBkMode(dc, OPAQUE);
		    break;
		case COLOR_NORMAL:
		    SetTextColor(dc, 0);
		    SetBkColor(dc, 0xffffff);
		    SetBkMode(dc, TRANSPARENT);
		    break;
		default:
		    break;
		}
		got_color = want_color;
	    }
	    if (!high && !underline) {
		want_font = pstate.font;
#if defined(GDI_DEBUG) /*[*/
		want_font_name = "Roman";
#endif /*]*/
	    } else if (high && !underline) {
		want_font = pstate.bold_font;
#if defined(GDI_DEBUG) /*[*/
		want_font_name = "Bold";
#endif /*]*/
	    } else if (!high && underline) {
		want_font = pstate.underscore_font;
#if defined(GDI_DEBUG) /*[*/
		want_font_name = "Underscore";
#endif /*]*/
	    } else {
		want_font = pstate.bold_underscore_font;
#if defined(GDI_DEBUG) /*[*/
		want_font_name = "Underscore";
#endif /*]*/
	    }
	    if (want_font != got_font) {
		SelectObject(dc, want_font);
		got_font = want_font;
#if defined(GDI_DEBUG) /*[*/
		vtrace("[gdi] selecting %s\n", want_font_name);
#endif /*]*/
	    }

	    /*
	     * Handle spaces and DBCS spaces (U+3000).
	     * If not reverse or underline, just skip over them.
	     * Otherwise, print a space or two spaces, using the
	     * right font and modes.
	     */
	    if (uc == ' ' || uc == 0x3000) {
		if (reverse || underline) {
		    status = ExtTextOut(dc, pstate.hmargin_pixels +
				(col * pstate.space_size.cx) -
				pchar.poffX,
			    pstate.vmargin_pixels +
				((pstate.out_row + row + 1) *
				 pstate.space_size.cy) -
				pchar.poffY,
			    0, NULL,
			    "  ",
			    (uc == 0x3000)? 2: 1,
			    pstate.dx);
		    if (status <= 0) {
			*fail = "ExtTextOut failed";
			rc = -1;
			goto done;
		    }
		}
		continue;
	    }

	    /*
	     * Emit one character at a time. This should be optimized to print
	     * strings of characters with the same attributes.
	     */
	    if (is_dbcs) {
		wchar_t w;
		INT wdx;

		w = (wchar_t)uc;
		wdx = pstate.space_size.cx;

		status = ExtTextOutW(dc,
			pstate.hmargin_pixels + (col * pstate.space_size.cx) -
			    pchar.poffX,
			pstate.vmargin_pixels +
			    ((pstate.out_row + row + 1) *
			     pstate.space_size.cy) -
			    pchar.poffY,
			0, NULL,
			&w, 1, &wdx);
		if (status <= 0) {
		    *fail = "ExtTextOutW failed";
		    rc = -1;
		    goto done;
		}
		continue;
	    }
	    c = (char)uc;
	    status = ExtTextOut(dc,
		    pstate.hmargin_pixels + (col * pstate.space_size.cx) -
			pchar.poffX,
		    pstate.vmargin_pixels +
			((pstate.out_row + row + 1) * pstate.space_size.cy) -
			pchar.poffY,
		    0, NULL,
		    &c, 1, pstate.dx);
#if defined(GDI_DEBUG) /*[*/
	    if (c != ' ') {
		vtrace("[gdi] row %d col %d x=%ld y=%ld '%c'\n",
			row, col,
			pstate.hmargin_pixels + (col * pstate.space_size.cx) -
			    pchar.poffX,
			pstate.vmargin_pixels +
			    ((pstate.out_row + row + 1) * pstate.space_size.cy) -
			    pchar.poffY,
			c);
	    }
#endif /*]*/
	    if (status <= 0) {
		*fail = "ExtTextOut failed";
		rc = -1;
		goto done;
	    }
	}
    }

    /* Tally the current screen and see if we need to go to a new page. */
    pstate.out_row += (row + 1); /* current screen plus a gap */
    pstate.screens++;
    if (pstate.out_row >= usable_rows || pstate.screens >= uparm.spp) {
	if (EndPage(dc) <= 0) {
	    *fail = "EndPage failed";
	    rc = -1;
	    goto done;
	}
	pstate.out_row = 0;
	pstate.screens = 0;
    }

done:
    GlobalUnlock(devmode);
    return rc;
}
Пример #18
0
/*
 * Initalize the named GDI printer. If the name is NULL, use the default
 * printer.
 */
static gdi_status_t
gdi_init(const char *printer_name, unsigned opts, const char **fail)
{
    char *default_printer_name;
    LPDEVMODE devmode;
    HDC dc;
    DOCINFO docinfo;
    DEVNAMES *devnames;
    int rmargin, bmargin; /* right margin, bottom margin */
    int maxphmargin, maxpvmargin;
    int i;
    static char get_fail[1024];
    int fheight, fwidth;

    memset(&pstate.dlg, '\0', sizeof(pstate.dlg));
    pstate.dlg.lStructSize = sizeof(pstate.dlg);
    pstate.dlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE |
	PD_NOSELECTION;

    if (printer_name == NULL || !*printer_name) {
	default_printer_name = get_default_printer_name(get_fail,
		sizeof(get_fail));
	if (default_printer_name == NULL) {
	    *fail = get_fail;
	    goto failed;
	}
	printer_name = default_printer_name;
    }
    if (!get_printer_device(printer_name, &pstate.dlg.hDevNames,
		&pstate.dlg.hDevMode)) {
	snprintf(get_fail, sizeof(get_fail),
		"GetPrinter(%s) failed: %s",
		printer_name, win32_strerror(GetLastError()));
	*fail = get_fail;
	goto failed;
    }
    if (uparm.orientation) {
	devmode = (LPDEVMODE)GlobalLock(pstate.dlg.hDevMode);
	devmode->dmFields |= DM_ORIENTATION;
	devmode->dmOrientation = uparm.orientation;
	GlobalUnlock(devmode);
    }

    if (opts & FPS_NO_DIALOG) {
	/* They don't want the print dialog. Allocate a DC for it. */
	devmode = (LPDEVMODE)GlobalLock(pstate.dlg.hDevMode);
	pstate.dlg.hDC = CreateDC("WINSPOOL", printer_name, NULL, devmode);
	GlobalUnlock(devmode);
	if (pstate.dlg.hDC == NULL) {
	    snprintf(get_fail, sizeof(get_fail), "Cannot create DC for "
		    "printer '%s'", printer_name);
	    *fail = get_fail;
	    goto failed;
	}
    } else {
	if (default_printer_name != NULL) {
	    Free(default_printer_name);
	    default_printer_name = NULL;
	}

	/* Pop up the dialog to get the printer characteristics. */
	if (!PrintDlg(&pstate.dlg)) {
	    return GDI_STATUS_CANCEL;
	}
    }
    dc = pstate.dlg.hDC;

    if (default_printer_name != NULL) {
	Free(default_printer_name);
	default_printer_name = NULL;
    }

    /* Find out the printer characteristics. */

    /* LOGPIXELSX and LOGPIXELSY are the pixels-per-inch for the printer. */
    pchar.ppiX = GetDeviceCaps(dc, LOGPIXELSX);
    if (pchar.ppiX <= 0) {
	*fail = "Can't get LOGPIXELSX";
	goto failed;
    }
    pchar.ppiY = GetDeviceCaps(dc, LOGPIXELSY);
    if (pchar.ppiY <= 0) {
	*fail = "Can't get LOGPIXELSY";
	goto failed;
    }

    /*
     * PHYSICALOFFSETX and PHYSICALOFFSETY are the fixed top and left-hand
     * margins, in pixels. Whatever you print is offset by these amounts, so
     * you have to subtract them from your coordinates. You cannot print in
     * these areas.
     */
    pchar.poffX = GetDeviceCaps(dc, PHYSICALOFFSETX);
    if (pchar.poffX < 0) {
	*fail = "Can't get PHYSICALOFFSETX";
	goto failed;
    }
    pchar.poffY = GetDeviceCaps(dc, PHYSICALOFFSETY);
    if (pchar.poffY < 0) {
	*fail = "Can't get PHYSICALOFFSETY";
	goto failed;
    }

    /*
     * HORZRES and VERTRES are the size of the usable area of the page, in
     * pixels. They implicitly give you the size of the right-hand and
     * bottom physical offsets.
     */
    pchar.horzres = GetDeviceCaps(dc, HORZRES);
    if (pchar.horzres <= 0) {
	*fail = "Can't get HORZRES";
	goto failed;
    }
    pchar.vertres = GetDeviceCaps(dc, VERTRES);
    if (pchar.vertres <= 0) {
	*fail = "Can't get VERTRES";
	goto failed;
    }

    /*
     * PHYSICALWIDTH and PHYSICALHEIGHT are the size of the entire area of
     * the page, in pixels.
     */
    pchar.pwidth = GetDeviceCaps(dc, PHYSICALWIDTH);
    if (pchar.pwidth <= 0) {
	*fail = "Can't get PHYSICALWIDTH";
	goto failed;
    }
    pchar.pheight = GetDeviceCaps(dc, PHYSICALHEIGHT);
    if (pchar.pheight <= 0) {
	*fail = "Can't get PHYSICALHEIGHT";
	goto failed;
    }

    /* Trace the device characteristics. */
    devnames = (DEVNAMES *)GlobalLock(pstate.dlg.hDevNames);
    vtrace("[gdi] Printer '%s' capabilities:\n",
	    (char *)devnames + devnames->wDeviceOffset);
    GlobalUnlock(devnames);
    vtrace("[gdi]  LOGPIXELSX %d LOGPIXELSY %d\n",
	    pchar.ppiX, pchar.ppiY);
    vtrace("[gdi]  PHYSICALOFFSETX %d PHYSICALOFFSETY %d\n",
	    pchar.poffX, pchar.poffY);
    vtrace("[gdi]  HORZRES %d VERTRES %d\n",
	    pchar.horzres, pchar.vertres);
    vtrace("[gdi]  PHYSICALWIDTH %d PHYSICALHEIGHT %d\n",
	    pchar.pwidth, pchar.pheight);

    /* Compute the scale factors (points to pixels). */
    pstate.xptscale = (FLOAT)pchar.ppiX / (FLOAT)PPI;
    pstate.yptscale = (FLOAT)pchar.ppiY / (FLOAT)PPI;

    /* Compute the implied right and bottom margins. */
    rmargin = pchar.pwidth - pchar.horzres - pchar.poffX;
    bmargin = pchar.pheight - pchar.vertres - pchar.poffY;
    if (rmargin > pchar.poffX) {
	maxphmargin = rmargin;
    } else {
	maxphmargin = pchar.poffX;
    }
    if (bmargin > pchar.poffY) {
	maxpvmargin = bmargin;
    } else {
	maxpvmargin = pchar.poffY;
    }
    vtrace("[gdi] maxphmargin is %d, maxpvmargin is %d pixels\n",
	    maxphmargin, maxpvmargin);

    /* Compute the margins in pixels. */
    pstate.hmargin_pixels = (int)(uparm.hmargin * pchar.ppiX);
    pstate.vmargin_pixels = (int)(uparm.vmargin * pchar.ppiY);

    /* See if the margins are too small. */
    if (pstate.hmargin_pixels < maxphmargin) {
	pstate.hmargin_pixels = maxphmargin;
	vtrace("[gdi] hmargin is too small, setting to %g\"\n",
		(float)pstate.hmargin_pixels / pchar.ppiX);
    }
    if (pstate.vmargin_pixels < maxpvmargin) {
	pstate.vmargin_pixels = maxpvmargin;
	vtrace("[gdi] vmargin is too small, setting to %g\"\n",
		(float)pstate.vmargin_pixels / pchar.ppiX);
    }

    /* See if the margins are too big. */
    if (pstate.hmargin_pixels * 2 >= pchar.horzres) {
	pstate.hmargin_pixels = pchar.ppiX;
	vtrace("[gdi] hmargin is too big, setting to 1\"\n");
    }
    if (pstate.vmargin_pixels * 2 >= pchar.vertres) {
	pstate.vmargin_pixels = pchar.ppiY;
	vtrace("[gdi] vmargin is too big, setting to 1\"\n");
    }

    /*
     * Compute the usable area in pixels. That's the physical page size
     * less the margins, now that we know that the margins are reasonable.
     */
    pstate.usable_xpixels = pchar.pwidth - (2 * pstate.hmargin_pixels);
    pstate.usable_ypixels = pchar.pheight - (2 * pstate.vmargin_pixels);
    vtrace("[gdi] usable area is %dx%d pixels\n",
	    pstate.usable_xpixels, pstate.usable_ypixels);

    /*
     * Create the Roman font.
     *
     * If they specified a particular font size, use that as the height,
     * and let the system pick the width.
     *
     * If they did not specify a font size, or chose "auto", then let the
     * "screens per page" drive what to do. If "screens per page" is set,
     * then divide the page Y pixels by the screens-per-page times the
     * display height to get the font height, and let the system pick the
     * width.
     *
     * Otherwise, divide the page X pixels by COLS to get the font width,
     * and let the system pick the height.
     */
    if (uparm.font_size) {
	/* User-specified fixed font size. */
	fheight = (int)(uparm.font_size * pstate.yptscale);
	fwidth = 0;
    } else {
	if (uparm.spp > 1) {
	    /*
	     * Scale the height so the specified number of screens will
	     * fit.
	     */
	    fheight = pstate.usable_ypixels /
		(uparm.spp * maxROWS /* spp screens */
		 + (uparm.spp - 1) /* spaces between screens */
		 + 2 /* space and caption*/ );
	    fwidth = 0;
	} else {
	    /*
	     * Scale the width so a screen will fit the page horizonally.
	     */
	    fheight = 0;
	    fwidth = pstate.usable_xpixels / maxCOLS;
	}
    }
    if (create_roman_font(dc, fheight, fwidth, fail) < 0) {
	goto failed;
    }

    /*
     * If we computed the font size, see if the other dimension is too
     * big. If it is, scale using the other dimension, which is guaranteed to
     * make the original computed dimension no bigger.
     *
     * XXX: This needs more testing.
     */
    if (!uparm.font_size) {
	if (fwidth == 0) {
	    /*
	     * We computed the height because spp > 1. See if the width
	     * overflows.
	     */
	    if (pstate.space_size.cx * maxCOLS > pstate.usable_xpixels) {
		vtrace("[gdi] font too wide, retrying\n");
		DeleteObject(pstate.font);
		pstate.font = NULL;

		fheight = 0;
		fwidth = pstate.usable_xpixels / maxCOLS;
		if (create_roman_font(dc, fheight, fwidth, fail) < 0) {
		    goto failed;
		}
	    }
	} else if (fheight == 0) {
	    /*
	     * We computed the width (spp <= 1). See if the height
	     * overflows.
	     */
	    if (pstate.space_size.cy * (maxROWS + 2) >
		    pstate.usable_xpixels) {
		vtrace("[gdi] font too high, retrying\n");
		DeleteObject(pstate.font);
		pstate.font = NULL;

		fheight = pstate.usable_xpixels / (maxROWS + 2);
		fwidth = 0;
		if (create_roman_font(dc, fheight, fwidth, fail) < 0) {
		    goto failed;
		}
	    }
	}
    }

    /* Create a bold font that is the same size, if possible. */
    pstate.bold_font = CreateFont(
	    pstate.space_size.cy,	/* height */
	    pstate.space_size.cx,	/* width */
	    0,			/* escapement */
	    0,			/* orientation */
	    FW_BOLD,		/* weight */
	    FALSE,			/* italic */
	    FALSE,			/* underline */
	    FALSE,			/* strikeout */
	    ANSI_CHARSET,		/* character set */
	    OUT_OUTLINE_PRECIS,	/* output precision */
	    CLIP_DEFAULT_PRECIS,	/* clip precision */
	    DEFAULT_QUALITY,	/* quality */
	    FIXED_PITCH|FF_DONTCARE,/* pitch and family */
	    uparm.font_name);	/* face */
    if (pstate.bold_font == NULL) {
	*fail = "CreateFont (bold) failed";
	goto failed;
    }

    /* Create an underscore font that is the same size, if possible. */
    pstate.underscore_font = CreateFont(
	    pstate.space_size.cy,	/* height */
	    pstate.space_size.cx,	/* width */
	    0,			/* escapement */
	    0,			/* orientation */
	    FW_NORMAL,		/* weight */
	    FALSE,			/* italic */
	    TRUE,			/* underline */
	    FALSE,			/* strikeout */
	    ANSI_CHARSET,		/* character set */
	    OUT_OUTLINE_PRECIS,	/* output precision */
	    CLIP_DEFAULT_PRECIS,	/* clip precision */
	    DEFAULT_QUALITY,	/* quality */
	    FIXED_PITCH|FF_DONTCARE,/* pitch and family */
	    uparm.font_name);	/* face */
    if (pstate.underscore_font == NULL) {
	*fail = "CreateFont (underscore) failed";
	goto failed;
    }

    /* Create a bold, underscore font that is the same size, if possible. */
    pstate.bold_underscore_font = CreateFont(
	    pstate.space_size.cy,	/* height */
	    pstate.space_size.cx,	/* width */
	    0,			/* escapement */
	    0,			/* orientation */
	    FW_BOLD,		/* weight */
	    FALSE,			/* italic */
	    TRUE,			/* underline */
	    FALSE,			/* strikeout */
	    ANSI_CHARSET,		/* character set */
	    OUT_OUTLINE_PRECIS,	/* output precision */
	    CLIP_DEFAULT_PRECIS,	/* clip precision */
	    DEFAULT_QUALITY,	/* quality */
	    FIXED_PITCH|FF_DONTCARE,/* pitch and family */
	    uparm.font_name);	/* face */
    if (pstate.bold_underscore_font == NULL) {
	*fail = "CreateFont (bold underscore) failed";
	goto failed;
    }

    /* Create a caption font. */
    pstate.caption_font = CreateFont(
	    pstate.space_size.cy,	/* height */
	    0,			/* width */
	    0,			/* escapement */
	    0,			/* orientation */
	    FW_NORMAL,		/* weight */
	    TRUE,			/* italic */
	    FALSE,			/* underline */
	    FALSE,			/* strikeout */
	    ANSI_CHARSET,		/* character set */
	    OUT_OUTLINE_PRECIS,	/* output precision */
	    CLIP_DEFAULT_PRECIS,	/* clip precision */
	    DEFAULT_QUALITY,	/* quality */
	    VARIABLE_PITCH|FF_DONTCARE,/* pitch and family */
	    "Times New Roman");	/* face */
    if (pstate.bold_underscore_font == NULL) {
	*fail = "CreateFont (bold underscore) failed";
	goto failed;
    }

    /* Set up the manual spacing array. */
    pstate.dx = Malloc(sizeof(INT) * maxCOLS);
    for (i = 0; i < maxCOLS; i++) {
	pstate.dx[i] = pstate.space_size.cx;
    }

    /* Fill in the document info. */
    memset(&docinfo, '\0', sizeof(docinfo));
    docinfo.cbSize = sizeof(docinfo);
    docinfo.lpszDocName = "wc3270 screen";

    /* Start the document. */
    if (StartDoc(dc, &docinfo) <= 0) {
	*fail = "StartDoc failed";
	goto failed;
    }

    return GDI_STATUS_SUCCESS;

failed:
    /* Clean up what we can and return failure. */
    if (default_printer_name != NULL) {
	Free(default_printer_name);
    }
    cleanup_fonts();
    return GDI_STATUS_ERROR;
}
Пример #19
0
/*
 * db_get --
 *	Look in the text buffers for a line, followed by the cache, followed
 *	by the database.
 *
 * PUBLIC: int db_get __P((SCR *, db_recno_t, u_int32_t, CHAR_T **, size_t *));
 */
int
db_get(SCR *sp, db_recno_t lno, u_int32_t flags, CHAR_T **pp, size_t *lenp)
		/* Line number. */ /* Pointer store. */ /* Length store. */
{
	DBT data, key;
	EXF *ep;
	TEXT *tp;
	db_recno_t l1, l2;
	const CHAR_T *wp;
	size_t wlen;
	size_t nlen;

	/*
	 * The underlying recno stuff handles zero by returning NULL, but
	 * have to have an OOB condition for the look-aside into the input
	 * buffer anyway.
	 */
	if (lno == 0)
		goto err1;

	/* Check for no underlying file. */
	if ((ep = sp->ep) == NULL) {
		ex_emsg(sp, NULL, EXM_NOFILEYET);
		goto err3;
	}

	if (LF_ISSET(DBG_NOCACHE))
		goto nocache;

	/*
	 * Look-aside into the TEXT buffers and see if the line we want
	 * is there.
	 */
	if (F_ISSET(sp, SC_TINPUT)) {
		l1 = ((TEXT *)sp->tiq.cqh_first)->lno;
		l2 = ((TEXT *)sp->tiq.cqh_last)->lno;
		if (l1 <= lno && l2 >= lno) {
#if defined(DEBUG) && 0
			vtrace(sp,
			    "retrieve TEXT buffer line %lu\n", (u_long)lno);
#endif
			for (tp = sp->tiq.cqh_first;
			    tp->lno != lno; tp = tp->q.cqe_next);
			if (lenp != NULL)
				*lenp = tp->len;
			if (pp != NULL)
				*pp = tp->lb;
			return (0);
		}
		/*
		 * Adjust the line number for the number of lines used
		 * by the text input buffers.
		 */
		if (lno > l2)
			lno -= l2 - l1;
	}

	/* Look-aside into the cache, and see if the line we want is there. */
	if (lno == sp->c_lno) {
#if defined(DEBUG) && 0
		vtrace(sp, "retrieve cached line %lu\n", (u_long)lno);
#endif
		if (lenp != NULL)
			*lenp = sp->c_len;
		if (pp != NULL)
			*pp = sp->c_lp;
		return (0);
	}
	sp->c_lno = OOBLNO;

nocache:
	nlen = 1024;
retry:
	/* data.size contains length in bytes */
	BINC_GOTO(sp, CHAR_T, sp->c_lp, sp->c_blen, nlen);

	/* Get the line from the underlying database. */
	memset(&key, 0, sizeof(key));
	key.data = &lno;
	key.size = sizeof(lno);
	memset(&data, 0, sizeof(data));
	data.data = sp->c_lp;
	data.ulen = sp->c_blen;
	data.flags = DB_DBT_USERMEM;
	switch (ep->db->get(ep->db, NULL, &key, &data, 0)) {
	case DB_BUFFER_SMALL:
		nlen = data.size;
		goto retry;
        default:
		goto err2;
	case DB_NOTFOUND:
err1:		if (LF_ISSET(DBG_FATAL))
err2:			db_err(sp, lno);
alloc_err:
err3:		if (lenp != NULL)
			*lenp = 0;
		if (pp != NULL)
			*pp = NULL;
		return (1);
	case 0:
		;
	}

	if (FILE2INT(sp, data.data, data.size, wp, wlen)) {
	    if (!F_ISSET(sp, SC_CONV_ERROR)) {
		F_SET(sp, SC_CONV_ERROR);
		msgq(sp, M_ERR, "324|Conversion error on line %d", lno);
	    }
	    goto err3;
	}

	/* Reset the cache. */
	if (wp != data.data) {
	    BINC_GOTOW(sp, sp->c_lp, sp->c_blen, wlen);
	    MEMCPYW(sp->c_lp, wp, wlen);
	}
	sp->c_lno = lno;
	sp->c_len = wlen;

#if defined(DEBUG) && 0
	vtrace(sp, "retrieve DB line %lu\n", (u_long)lno);
#endif
	if (lenp != NULL)
		*lenp = wlen;
	if (pp != NULL)
		*pp = sp->c_lp;
	return (0);
}
Пример #20
0
/*
 * Gather the user parameters from resources.
 */
static void
gdi_get_params(uparm_t *up)
{
    char *s;
    double d;
    unsigned long l;
    char *nextp;

    /* Orientation. */
    if ((s = get_resource(ResPrintTextOrientation)) != NULL) {
	if (!strcasecmp(s, "portrait")) {
	    up->orientation = DMORIENT_PORTRAIT;
	} else if (!strcasecmp(s, "landscape")) {
	    up->orientation = DMORIENT_LANDSCAPE;
	} else {
	    vtrace("gdi: unknown orientation '%s'\n", s);
	}
    }

    /* Horizontal margin. */
    if ((s = get_resource(ResPrintTextHorizontalMargin)) != NULL) {
	d = parse_margin(s, ResPrintTextHorizontalMargin);
	if (d > 0) {
	    up->hmargin = d;
	}
    }

    /* Vertical margin. */
    if ((s = get_resource(ResPrintTextVerticalMargin)) != NULL) {
	d = parse_margin(s, ResPrintTextVerticalMargin);
	if (d > 0) {
	    up->vmargin = d;
	}
    }

    /* Font name. */
    if ((s = get_resource(ResPrintTextFont)) != NULL) {
	up->font_name = s;
    }

    /* Font size. */
    if ((s = get_resource(ResPrintTextSize)) != NULL) {
	if (strcasecmp(s, "auto")) {
	    l = strtoul(s, &nextp, 0);
	    if (l > 0) {
		up->font_size = (int)l;
	    } else {
		vtrace("gdi: invalid %s '%s'\n", ResPrintTextSize, s);
	    }
	}
    }

    /* Screens per page. */
    if ((s = get_resource(ResPrintTextScreensPerPage)) != NULL) {
	l = strtoul(s, &nextp, 0);
	if (l > 0) {
	    up->spp = (int)l;
	} else {
	    vtrace("gdi: invalid %s '%s'\n", ResPrintTextScreensPerPage, s);
	}
    }
}
/*
 * vs_line --
 *	Update one line on the screen.
 *
 * PUBLIC: int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
 */
int
vs_line(SCR *sp, SMAP *smp, size_t *yp, size_t *xp)
{
	unsigned char *kp;
	GS *gp;
	SMAP *tsmp;
	size_t chlen = 0, cno_cnt, cols_per_screen, len, nlen;
	size_t offset_in_char, offset_in_line, oldx, oldy;
	size_t scno, skip_cols, skip_screens;
	int dne, is_cached, is_partial, is_tab, no_draw;
	int list_tab, list_dollar;
	CHAR_T *p;
	CHAR_T *cbp, *ecbp, cbuf[128];
	ARG_CHAR_T ch = L('\0');

#if defined(DEBUG) && 0
	vtrace(sp, "vs_line: row %u: line: %u off: %u\n",
	    smp - HMAP, smp->lno, smp->off);
#endif
	/*
	 * If ex modifies the screen after ex output is already on the screen,
	 * don't touch it -- we'll get scrolling wrong, at best.
	 */
	no_draw = 0;
	if (!F_ISSET(sp, SC_TINPUT_INFO) && VIP(sp)->totalcount > 1)
		no_draw = 1;
	if (F_ISSET(sp, SC_SCR_EXWROTE) && (size_t)(smp - HMAP) != LASTLINE(sp))
		no_draw = 1;

	/*
	 * Assume that, if the cache entry for the line is filled in, the
	 * line is already on the screen, and all we need to do is return
	 * the cursor position.  If the calling routine doesn't need the
	 * cursor position, we can just return.
	 */
	is_cached = SMAP_CACHE(smp);
	if (yp == NULL && (is_cached || no_draw))
		return (0);

	/*
	 * A nasty side effect of this routine is that it returns the screen
	 * position for the "current" character.  Not pretty, but this is the
	 * only routine that really knows what's out there.
	 *
	 * Move to the line.  This routine can be called by vs_sm_position(),
	 * which uses it to fill in the cache entry so it can figure out what
	 * the real contents of the screen are.  Because of this, we have to
	 * return to whereever we started from.
	 */
	gp = sp->gp;
	(void)gp->scr_cursor(sp, &oldy, &oldx);
	(void)gp->scr_move(sp, smp - HMAP, 0);

	/* Get the line. */
	dne = db_get(sp, smp->lno, 0, &p, &len);

	/*
	 * Special case if we're printing the info/mode line.  Skip printing
	 * the leading number, as well as other minor setup.  The only time
	 * this code paints the mode line is when the user is entering text
	 * for a ":" command, so we can put the code here instead of dealing
	 * with the empty line logic below.  This is a kludge, but it's pretty
	 * much confined to this module.
	 *
	 * Set the number of columns for this screen.
	 * Set the number of chars or screens to skip until a character is to
	 * be displayed.
	 */
	cols_per_screen = sp->cols;
	if (O_ISSET(sp, O_LEFTRIGHT)) {
		skip_screens = 0;
		skip_cols = smp->coff;
	} else {
		skip_screens = smp->soff - 1;
		skip_cols = skip_screens * cols_per_screen;
	}

	list_tab = O_ISSET(sp, O_LIST);
	if (F_ISSET(sp, SC_TINPUT_INFO))
		list_dollar = 0;
	else {
		list_dollar = list_tab;

		/*
		 * If O_NUMBER is set, the line doesn't exist and it's line
		 * number 1, i.e., an empty file, display the line number.
		 *
		 * If O_NUMBER is set, the line exists and the first character
		 * on the screen is the first character in the line, display
		 * the line number.
		 *
		 * !!!
		 * If O_NUMBER set, decrement the number of columns in the
		 * first screen.  DO NOT CHANGE THIS -- IT'S RIGHT!  The
		 * rest of the code expects this to reflect the number of
		 * columns in the first screen, regardless of the number of
		 * columns we're going to skip.
		 */
		if (O_ISSET(sp, O_NUMBER)) {
			cols_per_screen -= O_NUMBER_LENGTH;
			if ((!dne || smp->lno == 1) && skip_cols == 0) {
				nlen = snprintf((char*)cbuf,
				    sizeof(cbuf), O_NUMBER_FMT,
				    (unsigned long)smp->lno);
				(void)gp->scr_addstr(sp, (char*)cbuf, nlen);
			}
		}
	}

	/*
	 * Special case non-existent lines and the first line of an empty
	 * file.  In both cases, the cursor position is 0, but corrected
	 * as necessary for the O_NUMBER field, if it was displayed.
	 */
	if (dne || len == 0) {
		/* Fill in the cursor. */
		if (yp != NULL && smp->lno == sp->lno) {
			*yp = smp - HMAP;
			*xp = sp->cols - cols_per_screen;
		}

		/* If the line is on the screen, quit. */
		if (is_cached || no_draw)
			goto ret1;

		/* Set line cache information. */
		smp->c_sboff = smp->c_eboff = 0;
		smp->c_scoff = smp->c_eclen = 0;

		/*
		 * Lots of special cases for empty lines, but they only apply
		 * if we're displaying the first screen of the line.
		 */
		if (skip_cols == 0) {
			if (dne) {
				if (smp->lno == 1) {
					if (list_dollar) {
						ch = L('$');
						goto empty;
					}
				} else {
					ch = L('~');
					goto empty;
				}
			} else
				if (list_dollar) {
					ch = L('$');
empty:					(void)gp->scr_addstr(sp,
					    (const char *)KEY_NAME(sp, ch),
					    KEY_LEN(sp, ch));
				}
		}

		(void)gp->scr_clrtoeol(sp);
		(void)gp->scr_move(sp, oldy, oldx);
		return (0);
	}

	/* If we shortened this line in another screen, the cursor
	 * position may have fallen off.
	 */
	if (sp->lno == smp->lno && sp->cno >= len)
	    sp->cno = len - 1;

	/*
	 * If we just wrote this or a previous line, we cached the starting
	 * and ending positions of that line.  The way it works is we keep
	 * information about the lines displayed in the SMAP.  If we're
	 * painting the screen in the forward direction, this saves us from
	 * reformatting the physical line for every line on the screen.  This
	 * wins big on binary files with 10K lines.
	 *
	 * Test for the first screen of the line, then the current screen line,
	 * then the line behind us, then do the hard work.  Note, it doesn't
	 * do us any good to have a line in front of us -- it would be really
	 * hard to try and figure out tabs in the reverse direction, i.e. how
	 * many spaces a tab takes up in the reverse direction depends on
	 * what characters preceded it.
	 *
	 * Test for the first screen of the line.
	 */
	if (skip_cols == 0) {
		smp->c_sboff = offset_in_line = 0;
		smp->c_scoff = offset_in_char = 0;
		p = &p[offset_in_line];
		goto display;
	}

	/* Test to see if we've seen this exact line before. */
	if (is_cached) {
		offset_in_line = smp->c_sboff;
		offset_in_char = smp->c_scoff;
		p = &p[offset_in_line];

		/* Set cols_per_screen to 2nd and later line length. */
		if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen)
			cols_per_screen = sp->cols;
		goto display;
	}

	/* Test to see if we saw an earlier part of this line before. */
	if (smp != HMAP &&
	    SMAP_CACHE(tsmp = smp - 1) && tsmp->lno == smp->lno) {
		if (tsmp->c_eclen != tsmp->c_ecsize) {
			offset_in_line = tsmp->c_eboff;
			offset_in_char = tsmp->c_eclen;
		} else {
			offset_in_line = tsmp->c_eboff + 1;
			offset_in_char = 0;
		}

		/* Put starting info for this line in the cache. */
		smp->c_sboff = offset_in_line;
		smp->c_scoff = offset_in_char;
		p = &p[offset_in_line];

		/* Set cols_per_screen to 2nd and later line length. */
		if (O_ISSET(sp, O_LEFTRIGHT) || skip_cols > cols_per_screen)
			cols_per_screen = sp->cols;
		goto display;
	}

	scno = 0;
	offset_in_line = 0;
	offset_in_char = 0;

	/* Do it the hard way, for leftright scrolling screens. */
	if (O_ISSET(sp, O_LEFTRIGHT)) {
		for (; offset_in_line < len; ++offset_in_line) {
			chlen = (ch = (UCHAR_T)*p++) == L('\t') && !list_tab ?
			    TAB_OFF(scno) : KEY_COL(sp, ch);
			if ((scno += chlen) >= skip_cols)
				break;
		}

		/* Set cols_per_screen to 2nd and later line length. */
		cols_per_screen = sp->cols;

		/* Put starting info for this line in the cache. */
		if (offset_in_line >= len) {
			smp->c_sboff = offset_in_line;
			smp->c_scoff = 255;
		} else if (scno != skip_cols) {
			smp->c_sboff = offset_in_line;
			smp->c_scoff =
			    offset_in_char = chlen - (scno - skip_cols);
			--p;
		} else {
			smp->c_sboff = ++offset_in_line;
			smp->c_scoff = 0;
		}
	}

	/* Do it the hard way, for historic line-folding screens. */
	else {
		for (; offset_in_line < len; ++offset_in_line) {
			chlen = (ch = (UCHAR_T)*p++) == L('\t') && !list_tab ?
			    TAB_OFF(scno) : KEY_COL(sp, ch);
			if ((scno += chlen) < cols_per_screen)
				continue;
			scno -= cols_per_screen;

			/* Set cols_per_screen to 2nd and later line length. */
			cols_per_screen = sp->cols;

			/*
			 * If crossed the last skipped screen boundary, start
			 * displaying the characters.
			 */
			if (--skip_screens == 0)
				break;
		}

		/* Put starting info for this line in the cache. */
		if (scno != 0) {
			smp->c_sboff = offset_in_line;
			smp->c_scoff = offset_in_char = chlen - scno;
			--p;
		} else {
			smp->c_sboff = ++offset_in_line;
			smp->c_scoff = 0;
		}
	}

display:
	/*
	 * Set the number of characters to skip before reaching the cursor
	 * character.  Offset by 1 and use 0 as a flag value.  Vs_line is
	 * called repeatedly with a valid pointer to a cursor position.
	 * Don't fill anything in unless it's the right line and the right
	 * character, and the right part of the character...
	 */
	if (yp == NULL ||
	    smp->lno != sp->lno || sp->cno < offset_in_line ||
	    offset_in_line + cols_per_screen < sp->cno) {
		cno_cnt = 0;
		/* If the line is on the screen, quit. */
		if (is_cached || no_draw)
			goto ret1;
	} else
		cno_cnt = (sp->cno - offset_in_line) + 1;

	/* This is the loop that actually displays characters. */
	ecbp = (cbp = cbuf) + sizeof(cbuf)/sizeof(CHAR_T) - 1;
	for (is_partial = 0, scno = 0;
	    offset_in_line < len; ++offset_in_line, offset_in_char = 0) {
		if ((ch = (UCHAR_T)*p++) == L('\t') && !list_tab) {
			scno += chlen = TAB_OFF(scno) - offset_in_char;
			is_tab = 1;
		} else {
			scno += chlen = KEY_COL(sp, ch) - offset_in_char;
			is_tab = 0;
		}

		/*
		 * Only display up to the right-hand column.  Set a flag if
		 * the entire character wasn't displayed for use in setting
		 * the cursor.  If reached the end of the line, set the cache
		 * info for the screen.  Don't worry about there not being
		 * characters to display on the next screen, its lno/off won't
		 * match up in that case.
		 */
		if (scno >= cols_per_screen) {
			if (is_tab == 1) {
				chlen -= scno - cols_per_screen;
				smp->c_ecsize = smp->c_eclen = chlen;
				scno = cols_per_screen;
			} else {
				smp->c_ecsize = chlen;
				chlen -= scno - cols_per_screen;
				smp->c_eclen = chlen;

				if (scno > cols_per_screen)
					is_partial = 1;
			}
			smp->c_eboff = offset_in_line;

			/* Terminate the loop. */
			offset_in_line = len;
		}

		/*
		 * If the caller wants the cursor value, and this was the
		 * cursor character, set the value.  There are two ways to
		 * put the cursor on a character -- if it's normal display
		 * mode, it goes on the last column of the character.  If
		 * it's input mode, it goes on the first.  In normal mode,
		 * set the cursor only if the entire character was displayed.
		 */
		if (cno_cnt &&
		    --cno_cnt == 0 && (F_ISSET(sp, SC_TINPUT) || !is_partial)) {
			*yp = smp - HMAP;
			if (F_ISSET(sp, SC_TINPUT))
				if (is_partial)
					*xp = scno - smp->c_ecsize;
				else
					*xp = scno - chlen;
			else
				*xp = scno - 1;
			if (O_ISSET(sp, O_NUMBER) &&
			    !F_ISSET(sp, SC_TINPUT_INFO) && skip_cols == 0)
				*xp += O_NUMBER_LENGTH;

			/* If the line is on the screen, quit. */
			if (is_cached || no_draw)
				goto ret1;
		}

		/* If the line is on the screen, don't display anything. */
		if (is_cached || no_draw)
			continue;

#define	FLUSH {								\
	*cbp = '\0';							\
	(void)gp->scr_waddstr(sp, cbuf, cbp - cbuf);			\
	cbp = cbuf;							\
}
		/*
		 * Display the character.  We do tab expansion here because
		 * the screen interface doesn't have any way to set the tab
		 * length.  Note, it's theoretically possible for chlen to
		 * be larger than cbuf, if the user set a impossibly large
		 * tabstop.
		 */
		if (is_tab)
			while (chlen--) {
				if (cbp >= ecbp)
					FLUSH;
				*cbp++ = TABCH;
			}
		else {
			if (cbp + chlen >= ecbp)
				FLUSH;

			/* don't display half a wide character */
			if (is_partial && CHAR_WIDTH(sp, ch) > 1) {
				*cbp++ = ' ';
				break;
			}

			/* XXXX this needs some rethinking */
			if (INTISWIDE(ch)) {
				/* Put a space before non-spacing char. */
				if (CHAR_WIDTH(sp, ch) <= 0)
					*cbp++ = L(' ');
				*cbp++ = ch;
			} else
				for (kp = KEY_NAME(sp, ch) + offset_in_char; 
				     chlen--;)
					*cbp++ = (u_char)*kp++;
		}
	}

	if (scno < cols_per_screen) {
		/* If didn't paint the whole line, update the cache. */
		smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch);
		smp->c_eboff = len - 1;

		/*
		 * If not the info/mode line, and O_LIST set, and at the
		 * end of the line, and the line ended on this screen,
		 * add a trailing $.
		 */
		if (list_dollar) {
			++scno;

			chlen = KEY_LEN(sp, L('$'));
			if (cbp + chlen >= ecbp)
				FLUSH;
			for (kp = KEY_NAME(sp, L('$')); chlen--;)
				*cbp++ = *kp++;
		}

		/* If still didn't paint the whole line, clear the rest. */
		if (scno < cols_per_screen)
			(void)gp->scr_clrtoeol(sp);
	}

	/* Flush any buffered characters. */
	if (cbp > cbuf)
		FLUSH;

ret1:	(void)gp->scr_move(sp, oldy, oldx);
	return (0);
}
Пример #22
0
/*
 * log_line --
 *	Log a line change.
 *
 * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
 */
int
log_line(SCR *sp, db_recno_t lno, u_int action)
{
	DBT data, key;
	EXF *ep;
	size_t len;
	CHAR_T *lp;
	db_recno_t lcur;

	ep = sp->ep;
	if (F_ISSET(ep, F_NOLOG))
		return (0);

	/*
	 * XXX
	 *
	 * Kluge for vi.  Clear the EXF undo flag so that the
	 * next 'u' command does a roll-back, regardless.
	 */
	F_CLR(ep, F_UNDO);

	/* Put out one initial cursor record per set of changes. */
	if (ep->l_cursor.lno != OOBLNO) {
		if (log_cursor1(sp, LOG_CURSOR_INIT))
			return (1);
		ep->l_cursor.lno = OOBLNO;
		ep->l_win = sp->wp;
	} /*else if (ep->l_win != sp->wp) {
		printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
		return 1;
	}*/

	if ((sp->db_error = 
		__vi_change_log(ep->env, NULL, &ep->lsn_cur, 0, action, 
			    lno)) != 0) {
		msgq(sp, M_DBERR, "change_log");
		return 1;
	}

#if defined(DEBUG) && 0
	switch (action) {
	case LOG_LINE_APPEND_F:
		vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	case LOG_LINE_APPEND_B:
		vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	case LOG_LINE_DELETE_F:
		vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	case LOG_LINE_DELETE_B:
		vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	case LOG_LINE_RESET_F:
		vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	case LOG_LINE_RESET_B:
		vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
		    ep->l_cur, lno, len);
		break;
	}
#endif
	/* Reset high water mark. */
	ep->l_high = ++ep->l_cur;

	return (0);
}