/* * 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; }
/* * 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); }
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); } }
/* * 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; }
/* * 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); }
/* * 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); }
/** * 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()); } }
/* * 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)); }
/* * 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)); }
/* * 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; }
/* * 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); }
/** * 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); }
/* 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); }
/** * 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++; }
/** * 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); } } }
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); }
/* * 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; }
/* * 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; }
/* * 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); }
/* * 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); }
/* * 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); }