summaryrefslogtreecommitdiff
path: root/sys/src/cmd/unix/drawterm/gui-win32
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/unix/drawterm/gui-win32
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/unix/drawterm/gui-win32')
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/Makefile19
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/alloc.c23
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/cload.c10
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/draw.c22
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/load.c10
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/screen.c646
-rwxr-xr-xsys/src/cmd/unix/drawterm/gui-win32/wstrtoutf.c35
7 files changed, 765 insertions, 0 deletions
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/Makefile b/sys/src/cmd/unix/drawterm/gui-win32/Makefile
new file mode 100755
index 000000000..10547601f
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/Makefile
@@ -0,0 +1,19 @@
+ROOT=..
+include ../Make.config
+LIB=libgui.a
+
+OFILES=\
+ alloc.$O\
+ cload.$O\
+ draw.$O\
+ load.$O\
+ screen.$O
+
+default: $(LIB)
+$(LIB): $(OFILES)
+ $(AR) r $(LIB) $(OFILES)
+ $(RANLIB) $(LIB)
+
+%.$O: %.c
+ $(CC) $(CFLAGS) $*.c
+
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/alloc.c b/sys/src/cmd/unix/drawterm/gui-win32/alloc.c
new file mode 100755
index 000000000..cc7e97741
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/alloc.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+Memimage*
+allocmemimage(Rectangle r, ulong chan)
+{
+ return _allocmemimage(r, chan);
+}
+
+void
+freememimage(Memimage *i)
+{
+ _freememimage(i);
+}
+
+void
+memfillcolor(Memimage *i, ulong val)
+{
+ _memfillcolor(i, val);
+}
+
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/cload.c b/sys/src/cmd/unix/drawterm/gui-win32/cload.c
new file mode 100755
index 000000000..9d658ef85
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/cload.c
@@ -0,0 +1,10 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+int
+cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ return _cloadmemimage(i, r, data, ndata);
+}
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/draw.c b/sys/src/cmd/unix/drawterm/gui-win32/draw.c
new file mode 100755
index 000000000..eaac6d58a
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/draw.c
@@ -0,0 +1,22 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+void
+memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
+{
+ _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op));
+}
+
+ulong
+pixelbits(Memimage *m, Point p)
+{
+ return _pixelbits(m, p);
+}
+
+void
+memimageinit(void)
+{
+ _memimageinit();
+}
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/load.c b/sys/src/cmd/unix/drawterm/gui-win32/load.c
new file mode 100755
index 000000000..7cca3a6fd
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/load.c
@@ -0,0 +1,10 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+int
+loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ return _loadmemimage(i, r, data, ndata);
+}
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/screen.c b/sys/src/cmd/unix/drawterm/gui-win32/screen.c
new file mode 100755
index 000000000..0a656f27c
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/screen.c
@@ -0,0 +1,646 @@
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+
+#undef Rectangle
+#define Rectangle _Rectangle
+
+#include "u.h"
+#include "lib.h"
+#include "kern/dat.h"
+#include "kern/fns.h"
+#include "error.h"
+#include "user.h"
+#include <draw.h>
+#include <memdraw.h>
+#include "screen.h"
+#include "keyboard.h"
+
+Memimage *gscreen;
+Screeninfo screen;
+
+extern int mousequeue;
+static int depth;
+
+static HINSTANCE inst;
+static HWND window;
+static HPALETTE palette;
+static LOGPALETTE *logpal;
+static Lock gdilock;
+static BITMAPINFO *bmi;
+static HCURSOR hcursor;
+
+static void winproc(void *);
+static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+static void paletteinit(void);
+static void bmiinit(void);
+
+static int readybit;
+static Rendez rend;
+
+Point ZP;
+
+static int
+isready(void*a)
+{
+ return readybit;
+}
+
+void
+screeninit(void)
+{
+ int fmt;
+ int dx, dy;
+
+ memimageinit();
+ if(depth == 0)
+ depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL);
+ switch(depth){
+ case 32:
+ screen.dibtype = DIB_RGB_COLORS;
+ screen.depth = 32;
+ fmt = XRGB32;
+ break;
+ case 24:
+ screen.dibtype = DIB_RGB_COLORS;
+ screen.depth = 24;
+ fmt = RGB24;
+ break;
+ case 16:
+ screen.dibtype = DIB_RGB_COLORS;
+ screen.depth = 16;
+ fmt = RGB15; /* [sic] */
+ break;
+ case 8:
+ default:
+ screen.dibtype = DIB_PAL_COLORS;
+ screen.depth = 8;
+ depth = 8;
+ fmt = CMAP8;
+ break;
+ }
+ dx = GetDeviceCaps(GetDC(NULL), HORZRES);
+ dy = GetDeviceCaps(GetDC(NULL), VERTRES);
+
+ gscreen = allocmemimage(Rect(0,0,dx,dy), fmt);
+ kproc("winscreen", winproc, 0);
+ ksleep(&rend, isready, 0);
+}
+
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X)
+{
+ *r = gscreen->r;
+ *chan = gscreen->chan;
+ *depth = gscreen->depth;
+ *width = gscreen->width;
+ *softscreen = 1;
+
+ return gscreen->data->bdata;
+}
+
+void
+flushmemscreen(Rectangle r)
+{
+ screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP,
+ gscreen->width*sizeof(ulong));
+// Sleep(100);
+}
+
+void
+screenload(Rectangle r, int depth, uchar *p, Point pt, int step)
+{
+ int dx, dy, delx;
+ HDC hdc;
+ RECT winr;
+
+ if(depth != gscreen->depth)
+ panic("screenload: bad ldepth");
+
+ /*
+ * Sometimes we do get rectangles that are off the
+ * screen to the negative axes, for example, when
+ * dragging around a window border in a Move operation.
+ */
+ if(rectclip(&r, gscreen->r) == 0)
+ return;
+
+ if((step&3) != 0 || ((pt.x*depth)%32) != 0 || ((ulong)p&3) != 0)
+ panic("screenload: bad params %d %d %ux", step, pt.x, p);
+ dx = r.max.x - r.min.x;
+ dy = r.max.y - r.min.y;
+
+ if(dx <= 0 || dy <= 0)
+ return;
+
+ if(depth == 24)
+ delx = r.min.x % 4;
+ else
+ delx = r.min.x & (31/depth);
+
+ p += (r.min.y-pt.y)*step;
+ p += ((r.min.x-delx-pt.x)*depth)>>3;
+
+ if(GetWindowRect(window, &winr)==0)
+ return;
+ if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0)
+ return;
+
+ lock(&gdilock);
+
+ hdc = GetDC(window);
+ SelectPalette(hdc, palette, 0);
+ RealizePalette(hdc);
+
+//FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH));
+//GdiFlush();
+//Sleep(100);
+
+ bmi->bmiHeader.biWidth = (step*8)/depth;
+ bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */
+
+ StretchDIBits(hdc, r.min.x, r.min.y, dx, dy,
+ delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY);
+
+ ReleaseDC(window, hdc);
+
+ GdiFlush();
+
+ unlock(&gdilock);
+}
+
+static void
+winproc(void *a)
+{
+ WNDCLASS wc;
+ MSG msg;
+
+ inst = GetModuleHandle(NULL);
+
+ paletteinit();
+ bmiinit();
+ terminit();
+
+ wc.style = 0;
+ wc.lpfnWndProc = WindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = inst;
+ wc.hIcon = LoadIcon(inst, NULL);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = L"9pmgraphics";
+ RegisterClass(&wc);
+
+ window = CreateWindowEx(
+ 0, /* extended style */
+ L"9pmgraphics", /* class */
+ L"drawterm screen", /* caption */
+ WS_OVERLAPPEDWINDOW, /* style */
+ CW_USEDEFAULT, /* init. x pos */
+ CW_USEDEFAULT, /* init. y pos */
+ CW_USEDEFAULT, /* init. x size */
+ CW_USEDEFAULT, /* init. y size */
+ NULL, /* parent window (actually owner window for overlapped)*/
+ NULL, /* menu handle */
+ inst, /* program handle */
+ NULL /* create parms */
+ );
+
+ if(window == nil)
+ panic("can't make window\n");
+
+ ShowWindow(window, SW_SHOWDEFAULT);
+ UpdateWindow(window);
+
+ readybit = 1;
+ wakeup(&rend);
+
+ screen.reshaped = 0;
+
+ while(GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+// MessageBox(0, "winproc", "exits", MB_OK);
+ ExitProcess(0);
+}
+
+int
+col(int v, int n)
+{
+ int i, c;
+
+ c = 0;
+ for(i = 0; i < 8; i += n)
+ c |= v << (16-(n+i));
+ return c >> 8;
+}
+
+
+void
+paletteinit(void)
+{
+ PALETTEENTRY *pal;
+ int r, g, b, cr, cg, cb, v;
+ int num, den;
+ int i, j;
+
+ logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1);
+ if(logpal == nil)
+ panic("out of memory");
+ logpal->palVersion = 0x300;
+ logpal->palNumEntries = 256;
+ pal = logpal->palPalEntry;
+
+ for(r=0,i=0; r<4; r++) {
+ for(v=0; v<4; v++,i+=16){
+ for(g=0,j=v-r; g<4; g++) {
+ for(b=0; b<4; b++,j++){
+ den=r;
+ if(g>den)
+ den=g;
+ if(b>den)
+ den=b;
+ /* divide check -- pick grey shades */
+ if(den==0)
+ cr=cg=cb=v*17;
+ else{
+ num=17*(4*den+v);
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ pal[i+(j&15)].peRed = cr;
+ pal[i+(j&15)].peGreen = cg;
+ pal[i+(j&15)].peBlue = cb;
+ pal[i+(j&15)].peFlags = 0;
+ }
+ }
+ }
+ }
+ palette = CreatePalette(logpal);
+}
+
+
+void
+getcolor(ulong i, ulong *r, ulong *g, ulong *b)
+{
+ PALETTEENTRY *pal;
+
+ pal = logpal->palPalEntry;
+ *r = pal[i].peRed;
+ *g = pal[i].peGreen;
+ *b = pal[i].peBlue;
+}
+
+void
+bmiinit(void)
+{
+ ushort *p;
+ int i;
+
+ bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1);
+ if(bmi == 0)
+ panic("out of memory");
+ bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi->bmiHeader.biWidth = 0;
+ bmi->bmiHeader.biHeight = 0; /* - => origin upper left */
+ bmi->bmiHeader.biPlanes = 1;
+ bmi->bmiHeader.biBitCount = depth;
+ bmi->bmiHeader.biCompression = BI_RGB;
+ bmi->bmiHeader.biSizeImage = 0;
+ bmi->bmiHeader.biXPelsPerMeter = 0;
+ bmi->bmiHeader.biYPelsPerMeter = 0;
+ bmi->bmiHeader.biClrUsed = 0;
+ bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */
+
+ p = (ushort*)bmi->bmiColors;
+ for(i = 0; i < 256; i++)
+ p[i] = i;
+}
+
+LRESULT CALLBACK
+WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ PAINTSTRUCT paint;
+ HDC hdc;
+ LONG x, y, b;
+ int i;
+ Rectangle r;
+
+ switch(msg) {
+ case WM_CREATE:
+ break;
+ case WM_SETCURSOR:
+ /* User set */
+ if(hcursor != NULL) {
+ SetCursor(hcursor);
+ return 1;
+ }
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ case WM_MOUSEWHEEL:
+ if ((int)(wparam & 0xFFFF0000)>0)
+ b|=8;
+ else
+ b|=16;
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ x = LOWORD(lparam);
+ y = HIWORD(lparam);
+ b = 0;
+ if(wparam & MK_LBUTTON)
+ b = 1;
+ if(wparam & MK_MBUTTON)
+ b |= 2;
+ if(wparam & MK_RBUTTON) {
+ if(wparam & MK_SHIFT)
+ b |= 2;
+ else
+ b |= 4;
+ }
+ lock(&mouse.lk);
+ i = mouse.wi;
+ if(mousequeue) {
+ if(i == mouse.ri || mouse.lastb != b || mouse.trans) {
+ mouse.wi = (i+1)%Mousequeue;
+ if(mouse.wi == mouse.ri)
+ mouse.ri = (mouse.ri+1)%Mousequeue;
+ mouse.trans = mouse.lastb != b;
+ } else {
+ i = (i-1+Mousequeue)%Mousequeue;
+ }
+ } else {
+ mouse.wi = (i+1)%Mousequeue;
+ mouse.ri = i;
+ }
+ mouse.queue[i].xy.x = x;
+ mouse.queue[i].xy.y = y;
+ mouse.queue[i].buttons = b;
+ mouse.queue[i].msec = ticks();
+ mouse.lastb = b;
+ unlock(&mouse.lk);
+ wakeup(&mouse.r);
+ break;
+
+ case WM_CHAR:
+ /* repeat count is lparam & 0xf */
+ switch(wparam){
+ case '\n':
+ wparam = '\r';
+ break;
+ case '\r':
+ wparam = '\n';
+ break;
+ }
+ kbdputc(kbdq, wparam);
+ break;
+
+ case WM_SYSKEYUP:
+ break;
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ switch(wparam) {
+ case VK_MENU:
+ kbdputc(kbdq, Kalt);
+ break;
+ case VK_INSERT:
+ kbdputc(kbdq, Kins);
+ break;
+ case VK_DELETE:
+// kbdputc(kbdq, Kdel);
+ kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h
+ break;
+ case VK_UP:
+ kbdputc(kbdq, Kup);
+ break;
+ case VK_DOWN:
+ kbdputc(kbdq, Kdown);
+ break;
+ case VK_LEFT:
+ kbdputc(kbdq, Kleft);
+ break;
+ case VK_RIGHT:
+ kbdputc(kbdq, Kright);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_PALETTECHANGED:
+ if((HWND)wparam == hwnd)
+ break;
+ /* fall through */
+ case WM_QUERYNEWPALETTE:
+ hdc = GetDC(hwnd);
+ SelectPalette(hdc, palette, 0);
+ if(RealizePalette(hdc) != 0)
+ InvalidateRect(hwnd, nil, 0);
+ ReleaseDC(hwnd, hdc);
+ break;
+
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &paint);
+ r.min.x = paint.rcPaint.left;
+ r.min.y = paint.rcPaint.top;
+ r.max.x = paint.rcPaint.right;
+ r.max.y = paint.rcPaint.bottom;
+ flushmemscreen(r);
+ EndPaint(hwnd, &paint);
+ break;
+ case WM_COMMAND:
+ case WM_SETFOCUS:
+ case WM_DEVMODECHANGE:
+ case WM_WININICHANGE:
+ case WM_INITMENU:
+ default:
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+ return 0;
+}
+
+void
+mouseset(Point xy)
+{
+ POINT pt;
+
+ pt.x = xy.x;
+ pt.y = xy.y;
+ MapWindowPoints(window, 0, &pt, 1);
+ SetCursorPos(pt.x, pt.y);
+}
+
+void
+setcursor(void)
+{
+ HCURSOR nh;
+ int x, y, h, w;
+ uchar *sp, *cp;
+ uchar *and, *xor;
+
+ h = GetSystemMetrics(SM_CYCURSOR);
+ w = (GetSystemMetrics(SM_CXCURSOR)+7)/8;
+
+ and = mallocz(h*w, 1);
+ memset(and, 0xff, h*w);
+ xor = mallocz(h*w, 1);
+
+ lock(&cursor.lk);
+ for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) {
+ for(x=0; x<2; x++) {
+ and[y*w+x] = ~(*sp|*cp);
+ xor[y*w+x] = ~*sp & *cp;
+ cp++;
+ sp++;
+ }
+ }
+ nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y,
+ GetSystemMetrics(SM_CXCURSOR), h,
+ and, xor);
+ if(nh != NULL) {
+ SetCursor(nh);
+ if(hcursor != NULL)
+ DestroyCursor(hcursor);
+ hcursor = nh;
+ }
+ unlock(&cursor.lk);
+
+ free(and);
+ free(xor);
+
+ PostMessage(window, WM_SETCURSOR, (int)window, 0);
+}
+
+void
+cursorarrow(void)
+{
+ if(hcursor != 0) {
+ DestroyCursor(hcursor);
+ hcursor = 0;
+ }
+ SetCursor(LoadCursor(0, IDC_ARROW));
+ PostMessage(window, WM_SETCURSOR, (int)window, 0);
+}
+
+
+void
+setcolor(ulong index, ulong red, ulong green, ulong blue)
+{
+}
+
+
+uchar*
+clipreadunicode(HANDLE h)
+{
+ Rune *p;
+ int n;
+ uchar *q;
+
+ p = GlobalLock(h);
+ n = wstrutflen(p)+1;
+ q = malloc(n);
+ wstrtoutf(q, p, n);
+ GlobalUnlock(h);
+
+ return q;
+}
+
+uchar *
+clipreadutf(HANDLE h)
+{
+ uchar *p;
+
+ p = GlobalLock(h);
+ p = strdup(p);
+ GlobalUnlock(h);
+
+ return p;
+}
+
+char*
+clipread(void)
+{
+ HANDLE h;
+ uchar *p;
+
+ if(!OpenClipboard(window)) {
+ oserror();
+ return strdup("");
+ }
+
+ if((h = GetClipboardData(CF_UNICODETEXT)))
+ p = clipreadunicode(h);
+ else if((h = GetClipboardData(CF_TEXT)))
+ p = clipreadutf(h);
+ else {
+ oserror();
+ p = strdup("");
+ }
+
+ CloseClipboard();
+ return p;
+}
+
+int
+clipwrite(char *buf)
+{
+ HANDLE h;
+ char *p, *e;
+ Rune *rp;
+ int n = strlen(buf);
+
+ if(!OpenClipboard(window)) {
+ oserror();
+ return -1;
+ }
+
+ if(!EmptyClipboard()) {
+ oserror();
+ CloseClipboard();
+ return -1;
+ }
+
+ h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune));
+ if(h == NULL)
+ panic("out of memory");
+ rp = GlobalLock(h);
+ p = buf;
+ e = p+n;
+ while(p<e)
+ p += chartorune(rp++, p);
+ *rp = 0;
+ GlobalUnlock(h);
+
+ SetClipboardData(CF_UNICODETEXT, h);
+
+ h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1);
+ if(h == NULL)
+ panic("out of memory");
+ p = GlobalLock(h);
+ memcpy(p, buf, n);
+ p[n] = 0;
+ GlobalUnlock(h);
+
+ SetClipboardData(CF_TEXT, h);
+
+ CloseClipboard();
+ return n;
+}
+
+int
+atlocalconsole(void)
+{
+ return 1;
+}
diff --git a/sys/src/cmd/unix/drawterm/gui-win32/wstrtoutf.c b/sys/src/cmd/unix/drawterm/gui-win32/wstrtoutf.c
new file mode 100755
index 000000000..2cdc7fd8b
--- /dev/null
+++ b/sys/src/cmd/unix/drawterm/gui-win32/wstrtoutf.c
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+
+int
+wstrutflen(Rune *s)
+{
+ int n;
+
+ for(n=0; *s; n+=runelen(*s),s++)
+ ;
+ return n;
+}
+
+int
+wstrtoutf(char *s, Rune *t, int n)
+{
+ int i;
+ char *s0;
+
+ s0 = s;
+ if(n <= 0)
+ return wstrutflen(t)+1;
+ while(*t) {
+ if(n < UTFmax+1 && n < runelen(*t)+1) {
+ *s = 0;
+ return i+wstrutflen(t)+1;
+ }
+ i = runetochar(s, t);
+ s += i;
+ n -= i;
+ t++;
+ }
+ *s = 0;
+ return s-s0;
+}