diff --git a/uppsrc/CtrlCore/DrawX11.cpp b/uppsrc/CtrlCore/DrawX11.cpp index 3d3b5754b..b7f1ca177 100644 --- a/uppsrc/CtrlCore/DrawX11.cpp +++ b/uppsrc/CtrlCore/DrawX11.cpp @@ -1,464 +1,463 @@ -#include "CtrlCore.h" - -#ifdef GUI_X11 - -#define Time XTime -#define Font XFont -#define Display XDisplay -#define Picture XPicture - -#ifndef flagNOGTK -#include -#include -#include -#endif - -#undef Picture -#undef Time -#undef Font -#undef Display - -NAMESPACE_UPP - -#define LLOG(x) //LOG(x) -#define LTIMING(x) //TIMING(x) - -XDisplay *Xdisplay; -int Xscreenno; -Visual *Xvisual; -Window Xroot; -Screen *Xscreen; -Colormap Xcolormap; -int Xheight; -int Xwidth; -int XheightMM; -int XwidthMM; -int Xdepth; -dword Xblack; -dword Xwhite; -int Xconnection; -byte *Xmapcolor; -byte *Xunmapcolor; -bool Xpalette; - -dword (*Xgetpixel)(int r, int g, int b); - -EXITBLOCK -{ - if(Xdisplay) { -// No CloseDisplay for now... - XCloseDisplay(Xdisplay); - LLOG("Xdisplay closed"); - Xdisplay = NULL; - } - if(Xmapcolor) - delete[] Xmapcolor; - if(Xunmapcolor) - delete[] Xunmapcolor; -} - -void XError() -{ - Panic("X11 error !"); -} - -void XError(const char *s) -{ - Panic(String("X11 error:") + s + " !"); -} - -static int sAcs; - -bool sAllocColor(int xr, int xg, int xb) -{ - XColor ce; - ce.red = xr; - ce.green = xg; - ce.blue = xb; - ce.flags = DoRed | DoGreen | DoBlue; - if(!XAllocColor(Xdisplay, Xcolormap, &ce)) return false; - sAcs++; - return sAcs < 257; -} - -void sAllocColors() -{ - int r, g, b; - for(r = 0; r < 2; r++) - for(g = 0; g < 2; g++) - for(b = 0; b < 2; b++) - if(!sAllocColor(65535 * r, 65535 * g, 65535 * b)) return; - for(r = 0; r < 3; r++) - for(g = 0; g < 3; g++) - for(b = 0; b < 3; b++) - if((r == 1 || g == 1 || b == 1) && - !sAllocColor((65535 * r) / 2, (65535 * g) / 2, (65535 * b) / 2)) return; - for(r = 5; r >= 0; r--) - for(g = 5; g >= 0; g--) - for(b = 5; b >= 0; b--) - if((r != 0 && r != 5 || g != 0 && g != 5 || b != 0 && b != 5) && - !sAllocColor((65535 * r) / 5, (65535 * g) / 5, (65535 * b) / 5)) return; - for(r = 1; r <= 11; r += 2) - if(!sAllocColor((65535 * r) / 11, (65535 * r) / 11, (65535 * r) / 11)) return; - for(int r = 255; r >= 0; r--) - if(!sAllocColor(r << 8, r << 8, r << 8)) return; -} - -dword GetPseudoColorPixel(int r, int g, int b) -{ - return Xmapcolor[r * 11 / 255 * (24 * 12) + g * 23 / 255 * 12 + b * 11 / 255]; -} - -static -struct Xshift { - dword mask; - int bits; - int shift; - dword Do(int c) { return (c >> bits << shift) & mask; } -} -Xred, Xgreen, Xblue; - -Xshift CalcXShift(dword mask) -{ - Xshift f; - f.mask = mask; - f.shift = 0; - f.bits = 0; - while((mask & 1) == 0) { - mask >>= 1; - f.shift++; - } - while((mask & 1) == 1) { - mask >>= 1; - f.bits++; - } - f.bits = 8 - f.bits; - if(f.bits < 0) { - f.shift += f.bits; - f.bits = 0; - } - LLOG("xshift(" << FormatIntHex(mask) << "): mask = " - << FormatIntHex(f.mask) << ", bits = " << f.bits << ", shift = " << f.shift); - return f; -} - -dword GetTrueColorPixel(int r, int g, int b) -{ - return Xred.Do(r) | Xgreen.Do(g) | Xblue.Do(b); -} - -inline int ssq(int x) { return x * x; } - -void InitX11Draw(XDisplay *display) -{ - Xdisplay = display; - if(!Xdisplay) { - puts(NFormat("No X11 display, errno = %d, %s", errno, strerror(errno))); - fflush(stdout); - XError(); - } - Xscreenno = DefaultScreen(Xdisplay); - Xroot = RootWindow(Xdisplay, Xscreenno); - Xscreen = ScreenOfDisplay(Xdisplay, Xscreenno); - Xcolormap = DefaultColormap(Xdisplay, Xscreenno); -// Xcolormap = (Colormap)GDK().gdk_x11_colormap_get_xcolormap(GDK().gdk_rgb_get_colormap()); - Xheight = DisplayHeight(Xdisplay, Xscreenno); - Xwidth = DisplayWidth(Xdisplay, Xscreenno); - XheightMM = DisplayHeightMM(Xdisplay, Xscreenno); - XwidthMM = DisplayWidthMM(Xdisplay, Xscreenno); - LLOG("Xwidth = " << Xwidth << ", XwidthMM = " << XwidthMM); - LLOG("Xheight = " << Xheight << ", XheightMM = " << XheightMM); - Xdepth = DefaultDepth(Xdisplay, Xscreenno); - Xblack = BlackPixel(Xdisplay, 0); - Xwhite = WhitePixel(Xdisplay, 0); - Xconnection = XConnectionNumber(Xdisplay); - Xvisual = DefaultVisual(Xdisplay, Xscreenno); - Visual *v = Xvisual; - if(v->c_class == TrueColor) { - Xred = CalcXShift(v->red_mask); - Xgreen = CalcXShift(v->green_mask); - Xblue = CalcXShift(v->blue_mask); - Xgetpixel = GetTrueColorPixel; - } - else { - Xpalette = true; - sAllocColors(); - int colorcount = max(1 << Xdepth, 256); - Buffer cs(colorcount); - int i; - for(i = 0; i < colorcount; i++) - cs[i].pixel = i; - XQueryColors(Xdisplay, Xcolormap, cs, colorcount); - Xunmapcolor = new byte[3 * colorcount]; - for(i = 0; i < colorcount; i++) - { - Xunmapcolor[3 * i + 0] = cs[i].blue; - Xunmapcolor[3 * i + 1] = cs[i].green; - Xunmapcolor[3 * i + 2] = cs[i].red; - } - byte *cm = Xmapcolor = new byte[12 * 24 * 12]; - for(int r = 0; r < 12; r++) - for(int g = 0; g < 24; g++) - for(int b = 0; b < 12; b++) { - int mind = INT_MAX; - int mini; - for(int i = 0; i < colorcount; i++) { - int d = ssq(r * 255 / 11 - (cs[i].red >> 8)) + - ssq(g * 255 / 23 - (cs[i].green >> 8)) + - ssq(b * 255 / 11 - (cs[i].blue >> 8)); - if(d < mind) { - mini = i; - mind = d; - } - } - *cm++ = mini; - } - Xgetpixel = GetPseudoColorPixel; - } -// XFree(v); - - Font::SetStdFont(ScreenSans(12)); -} - -void InitX11Draw(const char *dispname) -{ -#ifdef flagNOGTK - if(!dispname || !*dispname) { - int f = Environment().Find("DISPLAY"); - dispname = (f >= 0 ? ~Environment()[f] : ":0.0"); - } - InitX11Draw(XOpenDisplay(dispname)); -#else - MemoryIgnoreLeaksBlock __; - const Vector& cmd = CommandLine(); - char **argv = (char**) MemoryAllocPermanent(sizeof(char *) * cmd.GetCount()); - for(int i = 0; i < cmd.GetCount(); i++) - argv[i] = PermanentCopy(cmd[i]); - int argc = cmd.GetCount(); - gtk_init (&argc, &argv); - GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL); - GdkDisplay *d = gtk_widget_get_display(w); - gdk_x11_display_get_xdisplay(d); - InitX11Draw(gdk_x11_display_get_xdisplay(d)); - gtk_widget_destroy(w); -#endif -} - -void SetClip(GC gc, XftDraw *xftdraw, const Vector& cl) -{ - GuiLock __; - LTIMING("SetClip"); - Buffer xr(cl.GetCount()); - LLOG("SetClip"); - for(int i = 0; i < cl.GetCount(); i++) { - XRectangle& r = xr[i]; - const Rect& cr = cl[i]; - LLOG("[" << i << "] = " << cr); - r.x = cr.left; - r.y = cr.top; - r.width = cr.Width(); - r.height = cr.Height(); - } - XSetClipRectangles(Xdisplay, gc, 0, 0, xr, cl.GetCount(), Unsorted); - LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw)); - XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount()); - LLOG("//XftDrawSetClipRectangles"); -} - -void SystemDraw::CloneClip() -{ - if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) { - cloff.Top().clipi = clip.GetCount(); - Vector& c = clip.Add(); - c <<= clip[clip.GetCount() - 2]; - } -} - -void SystemDraw::SetForeground(Color color) -{ - GuiLock __; - LTIMING("SetForeground"); - int p = GetXPixel(color.GetR(), color.GetG(), color.GetB()); - if(p == foreground) return; - LTIMING("XSetForeground"); - LLOG("XSetForeground " << color); - foreground = p; - XSetForeground(Xdisplay, gc, foreground); -} - -void SystemDraw::SetClip() { - GuiLock __; - drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); - if(!clip.IsEmpty()) { - const Vector& topclip = clip.Top(); - drawingclip = Rect(0, 0, 0, 0); - if(!topclip.IsEmpty()) { - drawingclip = topclip[0]; - for(int i = 1; i < topclip.GetCount(); i++) - drawingclip |= topclip[i]; - } - drawingclip -= actual_offset; - } - if(dw == Xroot) return; - LTIMING("SetClip"); - UPP::SetClip(gc, xftdraw, clip.Top()); -} - -void SystemDraw::SetLineStyle(int width) -{ - GuiLock __; - if(width == linewidth) return; - linewidth = width; - if(IsNull(width)) - width = 1; - if(width < PEN_SOLID) { - static const char dash[] = { 18, 6 }; - static const char dot[] = { 3, 3 }; - static const char dashdot[] = { 9, 6, 3, 6 }; - static const char dashdotdot[] = { 9, 3, 3, 3, 3, 3 }; - static struct { - const char *dash; - int len; - } ds[] = { - { dash, __countof(dash) }, - { dot, __countof(dot) }, - { dashdot, __countof(dashdot) }, - { dashdotdot, __countof(dashdotdot) } - }; - int i = -(width - PEN_DASH); - ASSERT(i >= 0 && i < 4); - XSetDashes(Xdisplay, gc, 0, ds[i].dash, ds[i].len); - } - XSetLineAttributes(Xdisplay, gc, max(width, 1), - width < PEN_SOLID ? LineOnOffDash : LineSolid, CapRound, JoinRound); -} - -void SystemDraw::Init() -{ - GuiLock __; - pageSize = Size(Xwidth, Xheight); - cloff.Clear(); - clip.Clear(); - drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); - foreground = linewidth = Null; -} - -void SystemDraw::Init(const Vector& _clip, Point _offset) -{ - GuiLock __; - Init(); - clip.Add() <<= _clip; - offset.Add(_offset); - actual_offset = _offset; - Cloff& f = cloff.Add(); - f.offseti = 0; - f.clipi = 0; - SetClip(); -} - -dword SystemDraw::GetInfo() const -{ - return 0; -} - -Size SystemDraw::GetPageSize() const -{ - return pageSize; -} - -SystemDraw::SystemDraw() -{ - GuiLock __; - dw = None; - gc = None; - actual_offset = Point(0, 0); - Init(); -} - -Size SystemDraw::GetNativeDpi() const -{ - return Size(96, 96); -} - -void SystemDraw::BeginNative() {} -void SystemDraw::EndNative() {} - -int SystemDraw::GetCloffLevel() const -{ - return cloff.GetCount(); -} - -Rect SystemDraw::GetClip() const -{ - LLOG("Draw::GetClipOp; #clip = " << clip.GetCount() << ", #cloff = " << cloff.GetCount() - << ", clipi = " << cloff.Top().clipi); - const Vector& cl = clip[cloff.Top().clipi]; - Rect box(0, 0, 0, 0); - if(!cl.GetCount()) return box; - box = cl[0]; - LLOG("cl[0] = " << box); - for(int i = 1; i < cl.GetCount(); i++) { - LLOG("cl[" << i << "] = " << cl[i]); - box |= cl[i]; - } - LLOG("out box = " << box << ", actual offset = " << actual_offset); - return box - actual_offset; -} - -SystemDraw::SystemDraw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector& _clip) -{ - LLOG("SystemDraw"); - dw = _dw; - gc = _gc; - xftdraw = _xftdraw; - Init(_clip); -} - -void BackDraw::Create(SystemDraw& w, int cx, int cy) -{ - GuiLock __; - LLOG("Creating BackDraw " << cx << "x" << cy); - Destroy(); - size.cx = cx; - size.cy = cy; - dw = XCreatePixmap(Xdisplay, w.GetDrawable(), max(cx, 1), max(cy, 1), Xdepth); - gc = XCreateGC(Xdisplay, dw, 0, 0); - xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, - DefaultVisual(Xdisplay, Xscreenno), Xcolormap); - Vector clip; - clip.Add(RectC(0, 0, cx, cy)); - Init(clip, Point(0, 0)); -} - -void BackDraw::Put(SystemDraw& w, int x, int y) -{ - GuiLock __; - LLOG("Putting BackDraw"); - ASSERT(dw != None); - XCopyArea(Xdisplay, dw, w.GetDrawable(), w.GetGC(), 0, 0, size.cx, size.cy, - x + w.GetOffset().x, y + w.GetOffset().y); -} - -void BackDraw::Destroy() -{ - GuiLock __; - if(dw != None) { - XftDrawDestroy(xftdraw); - XFreePixmap(Xdisplay, dw); - XFreeGC(Xdisplay, gc); - } -} - -bool ScreenInPaletteMode() -{ - return Xpalette; -} - -Size GetScreenSize() -{ - return Size(Xwidth, Xheight); -} - -END_UPP_NAMESPACE - -#endif +#include "CtrlCore.h" + +#ifdef GUI_X11 + +#define Time XTime +#define Font XFont +#define Display XDisplay +#define Picture XPicture + +#ifndef flagNOGTK +#include +#include +#include +#endif + +#undef Picture +#undef Time +#undef Font +#undef Display + +NAMESPACE_UPP + +#define LLOG(x) //LOG(x) +#define LTIMING(x) //TIMING(x) + +XDisplay *Xdisplay; +int Xscreenno; +Visual *Xvisual; +Window Xroot; +Screen *Xscreen; +Colormap Xcolormap; +int Xheight; +int Xwidth; +int XheightMM; +int XwidthMM; +int Xdepth; +dword Xblack; +dword Xwhite; +int Xconnection; +byte *Xmapcolor; +byte *Xunmapcolor; +bool Xpalette; + +dword (*Xgetpixel)(int r, int g, int b); + +EXITBLOCK +{ + if(Xdisplay) { + XCloseDisplay(Xdisplay); + LLOG("Xdisplay closed"); + Xdisplay = NULL; + } + if(Xmapcolor) + delete[] Xmapcolor; + if(Xunmapcolor) + delete[] Xunmapcolor; +} + +void XError() +{ + Panic("X11 error !"); +} + +void XError(const char *s) +{ + Panic(String("X11 error:") + s + " !"); +} + +static int sAcs; + +bool sAllocColor(int xr, int xg, int xb) +{ + XColor ce; + ce.red = xr; + ce.green = xg; + ce.blue = xb; + ce.flags = DoRed | DoGreen | DoBlue; + if(!XAllocColor(Xdisplay, Xcolormap, &ce)) return false; + sAcs++; + return sAcs < 257; +} + +void sAllocColors() +{ + int r, g, b; + for(r = 0; r < 2; r++) + for(g = 0; g < 2; g++) + for(b = 0; b < 2; b++) + if(!sAllocColor(65535 * r, 65535 * g, 65535 * b)) return; + for(r = 0; r < 3; r++) + for(g = 0; g < 3; g++) + for(b = 0; b < 3; b++) + if((r == 1 || g == 1 || b == 1) && + !sAllocColor((65535 * r) / 2, (65535 * g) / 2, (65535 * b) / 2)) return; + for(r = 5; r >= 0; r--) + for(g = 5; g >= 0; g--) + for(b = 5; b >= 0; b--) + if((r != 0 && r != 5 || g != 0 && g != 5 || b != 0 && b != 5) && + !sAllocColor((65535 * r) / 5, (65535 * g) / 5, (65535 * b) / 5)) return; + for(r = 1; r <= 11; r += 2) + if(!sAllocColor((65535 * r) / 11, (65535 * r) / 11, (65535 * r) / 11)) return; + for(int r = 255; r >= 0; r--) + if(!sAllocColor(r << 8, r << 8, r << 8)) return; +} + +dword GetPseudoColorPixel(int r, int g, int b) +{ + return Xmapcolor[r * 11 / 255 * (24 * 12) + g * 23 / 255 * 12 + b * 11 / 255]; +} + +static +struct Xshift { + dword mask; + int bits; + int shift; + dword Do(int c) { return (c >> bits << shift) & mask; } +} +Xred, Xgreen, Xblue; + +Xshift CalcXShift(dword mask) +{ + Xshift f; + f.mask = mask; + f.shift = 0; + f.bits = 0; + while((mask & 1) == 0) { + mask >>= 1; + f.shift++; + } + while((mask & 1) == 1) { + mask >>= 1; + f.bits++; + } + f.bits = 8 - f.bits; + if(f.bits < 0) { + f.shift += f.bits; + f.bits = 0; + } + LLOG("xshift(" << FormatIntHex(mask) << "): mask = " + << FormatIntHex(f.mask) << ", bits = " << f.bits << ", shift = " << f.shift); + return f; +} + +dword GetTrueColorPixel(int r, int g, int b) +{ + return Xred.Do(r) | Xgreen.Do(g) | Xblue.Do(b); +} + +inline int ssq(int x) { return x * x; } + +void InitX11Draw(XDisplay *display) +{ + Xdisplay = display; + if(!Xdisplay) { + puts(NFormat("No X11 display, errno = %d, %s", errno, strerror(errno))); + fflush(stdout); + XError(); + } + Xscreenno = DefaultScreen(Xdisplay); + Xroot = RootWindow(Xdisplay, Xscreenno); + Xscreen = ScreenOfDisplay(Xdisplay, Xscreenno); + Xcolormap = DefaultColormap(Xdisplay, Xscreenno); +// Xcolormap = (Colormap)GDK().gdk_x11_colormap_get_xcolormap(GDK().gdk_rgb_get_colormap()); + Xheight = DisplayHeight(Xdisplay, Xscreenno); + Xwidth = DisplayWidth(Xdisplay, Xscreenno); + XheightMM = DisplayHeightMM(Xdisplay, Xscreenno); + XwidthMM = DisplayWidthMM(Xdisplay, Xscreenno); + LLOG("Xwidth = " << Xwidth << ", XwidthMM = " << XwidthMM); + LLOG("Xheight = " << Xheight << ", XheightMM = " << XheightMM); + Xdepth = DefaultDepth(Xdisplay, Xscreenno); + Xblack = BlackPixel(Xdisplay, 0); + Xwhite = WhitePixel(Xdisplay, 0); + Xconnection = XConnectionNumber(Xdisplay); + Xvisual = DefaultVisual(Xdisplay, Xscreenno); + Visual *v = Xvisual; + if(v->c_class == TrueColor) { + Xred = CalcXShift(v->red_mask); + Xgreen = CalcXShift(v->green_mask); + Xblue = CalcXShift(v->blue_mask); + Xgetpixel = GetTrueColorPixel; + } + else { + Xpalette = true; + sAllocColors(); + int colorcount = max(1 << Xdepth, 256); + Buffer cs(colorcount); + int i; + for(i = 0; i < colorcount; i++) + cs[i].pixel = i; + XQueryColors(Xdisplay, Xcolormap, cs, colorcount); + Xunmapcolor = new byte[3 * colorcount]; + for(i = 0; i < colorcount; i++) + { + Xunmapcolor[3 * i + 0] = cs[i].blue; + Xunmapcolor[3 * i + 1] = cs[i].green; + Xunmapcolor[3 * i + 2] = cs[i].red; + } + byte *cm = Xmapcolor = new byte[12 * 24 * 12]; + for(int r = 0; r < 12; r++) + for(int g = 0; g < 24; g++) + for(int b = 0; b < 12; b++) { + int mind = INT_MAX; + int mini; + for(int i = 0; i < colorcount; i++) { + int d = ssq(r * 255 / 11 - (cs[i].red >> 8)) + + ssq(g * 255 / 23 - (cs[i].green >> 8)) + + ssq(b * 255 / 11 - (cs[i].blue >> 8)); + if(d < mind) { + mini = i; + mind = d; + } + } + *cm++ = mini; + } + Xgetpixel = GetPseudoColorPixel; + } +// XFree(v); + + Font::SetStdFont(ScreenSans(12)); +} + +void InitX11Draw(const char *dispname) +{ +#ifdef flagNOGTK + if(!dispname || !*dispname) { + int f = Environment().Find("DISPLAY"); + dispname = (f >= 0 ? ~Environment()[f] : ":0.0"); + } + InitX11Draw(XOpenDisplay(dispname)); +#else + MemoryIgnoreLeaksBlock __; + const Vector& cmd = CommandLine(); + char **argv = (char**) MemoryAllocPermanent(sizeof(char *) * cmd.GetCount()); + for(int i = 0; i < cmd.GetCount(); i++) + argv[i] = PermanentCopy(cmd[i]); + int argc = cmd.GetCount(); + gtk_init (&argc, &argv); + GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + GdkDisplay *d = gtk_widget_get_display(w); + gdk_x11_display_get_xdisplay(d); + InitX11Draw(gdk_x11_display_get_xdisplay(d)); + gtk_widget_destroy(w); +#endif +} + +void SetClip(GC gc, XftDraw *xftdraw, const Vector& cl) +{ + GuiLock __; + LTIMING("SetClip"); + Buffer xr(cl.GetCount()); + LLOG("SetClip"); + for(int i = 0; i < cl.GetCount(); i++) { + XRectangle& r = xr[i]; + const Rect& cr = cl[i]; + LLOG("[" << i << "] = " << cr); + r.x = cr.left; + r.y = cr.top; + r.width = cr.Width(); + r.height = cr.Height(); + } + XSetClipRectangles(Xdisplay, gc, 0, 0, xr, cl.GetCount(), Unsorted); + LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw)); + XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount()); + LLOG("//XftDrawSetClipRectangles"); +} + +void SystemDraw::CloneClip() +{ + if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) { + cloff.Top().clipi = clip.GetCount(); + Vector& c = clip.Add(); + c <<= clip[clip.GetCount() - 2]; + } +} + +void SystemDraw::SetForeground(Color color) +{ + GuiLock __; + LTIMING("SetForeground"); + int p = GetXPixel(color.GetR(), color.GetG(), color.GetB()); + if(p == foreground) return; + LTIMING("XSetForeground"); + LLOG("XSetForeground " << color); + foreground = p; + XSetForeground(Xdisplay, gc, foreground); +} + +void SystemDraw::SetClip() { + GuiLock __; + drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); + if(!clip.IsEmpty()) { + const Vector& topclip = clip.Top(); + drawingclip = Rect(0, 0, 0, 0); + if(!topclip.IsEmpty()) { + drawingclip = topclip[0]; + for(int i = 1; i < topclip.GetCount(); i++) + drawingclip |= topclip[i]; + } + drawingclip -= actual_offset; + } + if(dw == Xroot) return; + LTIMING("SetClip"); + UPP::SetClip(gc, xftdraw, clip.Top()); +} + +void SystemDraw::SetLineStyle(int width) +{ + GuiLock __; + if(width == linewidth) return; + linewidth = width; + if(IsNull(width)) + width = 1; + if(width < PEN_SOLID) { + static const char dash[] = { 18, 6 }; + static const char dot[] = { 3, 3 }; + static const char dashdot[] = { 9, 6, 3, 6 }; + static const char dashdotdot[] = { 9, 3, 3, 3, 3, 3 }; + static struct { + const char *dash; + int len; + } ds[] = { + { dash, __countof(dash) }, + { dot, __countof(dot) }, + { dashdot, __countof(dashdot) }, + { dashdotdot, __countof(dashdotdot) } + }; + int i = -(width - PEN_DASH); + ASSERT(i >= 0 && i < 4); + XSetDashes(Xdisplay, gc, 0, ds[i].dash, ds[i].len); + } + XSetLineAttributes(Xdisplay, gc, max(width, 1), + width < PEN_SOLID ? LineOnOffDash : LineSolid, CapRound, JoinRound); +} + +void SystemDraw::Init() +{ + GuiLock __; + pageSize = Size(Xwidth, Xheight); + cloff.Clear(); + clip.Clear(); + drawingclip = Rect(-(INT_MAX >> 1), -(INT_MAX >> 1), +(INT_MAX >> 1), +(INT_MAX >> 1)); + foreground = linewidth = Null; +} + +void SystemDraw::Init(const Vector& _clip, Point _offset) +{ + GuiLock __; + Init(); + clip.Add() <<= _clip; + offset.Add(_offset); + actual_offset = _offset; + Cloff& f = cloff.Add(); + f.offseti = 0; + f.clipi = 0; + SetClip(); +} + +dword SystemDraw::GetInfo() const +{ + return 0; +} + +Size SystemDraw::GetPageSize() const +{ + return pageSize; +} + +SystemDraw::SystemDraw() +{ + GuiLock __; + dw = None; + gc = None; + actual_offset = Point(0, 0); + Init(); +} + +Size SystemDraw::GetNativeDpi() const +{ + return Size(96, 96); +} + +void SystemDraw::BeginNative() {} +void SystemDraw::EndNative() {} + +int SystemDraw::GetCloffLevel() const +{ + return cloff.GetCount(); +} + +Rect SystemDraw::GetClip() const +{ + LLOG("Draw::GetClipOp; #clip = " << clip.GetCount() << ", #cloff = " << cloff.GetCount() + << ", clipi = " << cloff.Top().clipi); + const Vector& cl = clip[cloff.Top().clipi]; + Rect box(0, 0, 0, 0); + if(!cl.GetCount()) return box; + box = cl[0]; + LLOG("cl[0] = " << box); + for(int i = 1; i < cl.GetCount(); i++) { + LLOG("cl[" << i << "] = " << cl[i]); + box |= cl[i]; + } + LLOG("out box = " << box << ", actual offset = " << actual_offset); + return box - actual_offset; +} + +SystemDraw::SystemDraw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector& _clip) +{ + LLOG("SystemDraw"); + dw = _dw; + gc = _gc; + xftdraw = _xftdraw; + Init(_clip); +} + +void BackDraw::Create(SystemDraw& w, int cx, int cy) +{ + GuiLock __; + LLOG("Creating BackDraw " << cx << "x" << cy); + Destroy(); + size.cx = cx; + size.cy = cy; + dw = XCreatePixmap(Xdisplay, w.GetDrawable(), max(cx, 1), max(cy, 1), Xdepth); + gc = XCreateGC(Xdisplay, dw, 0, 0); + xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, + DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + Vector clip; + clip.Add(RectC(0, 0, cx, cy)); + Init(clip, Point(0, 0)); +} + +void BackDraw::Put(SystemDraw& w, int x, int y) +{ + GuiLock __; + LLOG("Putting BackDraw"); + ASSERT(dw != None); + XCopyArea(Xdisplay, dw, w.GetDrawable(), w.GetGC(), 0, 0, size.cx, size.cy, + x + w.GetOffset().x, y + w.GetOffset().y); +} + +void BackDraw::Destroy() +{ + GuiLock __; + if(dw != None) { + XftDrawDestroy(xftdraw); + XFreePixmap(Xdisplay, dw); + XFreeGC(Xdisplay, gc); + } +} + +bool ScreenInPaletteMode() +{ + return Xpalette; +} + +Size GetScreenSize() +{ + return Size(Xwidth, Xheight); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/CtrlLib/ArrayCtrl.cpp b/uppsrc/CtrlLib/ArrayCtrl.cpp index 2994ba9e6..cc1970f07 100644 --- a/uppsrc/CtrlLib/ArrayCtrl.cpp +++ b/uppsrc/CtrlLib/ArrayCtrl.cpp @@ -72,11 +72,6 @@ ArrayCtrl::Column& ArrayCtrl::Column::Ctrls(Callback2&> _factory) return *this; } -static void sPerformSimple(int, One& x, Callback1&> factory) -{ - factory(x); -} - void ArrayCtrl::Column::Factory1(int, One& x) { factory1(x); @@ -2879,7 +2874,6 @@ ArrayCtrl::Column& ArrayOption::AddColumn(ArrayCtrl& ac, const Id& id, const cha void ArrayOption::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const { - bool focusCursor = (style & (CURSOR | SELECT)) && (style & FOCUS); bool gray = (array && !array->IsEnabled()); w.DrawRect(r, paper); diff --git a/uppsrc/CtrlLib/Button.cpp b/uppsrc/CtrlLib/Button.cpp index 284f225af..ffc4818e6 100644 --- a/uppsrc/CtrlLib/Button.cpp +++ b/uppsrc/CtrlLib/Button.cpp @@ -556,7 +556,7 @@ void Option::Paint(Draw& w) { w.DrawRect(0, 0, sz.cx, sz.cy, SColorFace); Size isz = CtrlsImg::O0().GetSize(); - Size tsz; + Size tsz(0, 0); int ix = 0, iy = 0, ty = 0; if(showlabel) { diff --git a/uppsrc/CtrlLib/FileSel.cpp b/uppsrc/CtrlLib/FileSel.cpp index 5fec95f0d..79542e78c 100644 --- a/uppsrc/CtrlLib/FileSel.cpp +++ b/uppsrc/CtrlLib/FileSel.cpp @@ -1475,7 +1475,7 @@ void FileSel::Serialize(Stream& s) { int version = 10; s / version; String ad = ~dir; - int dummy; + int dummy = 0; if(version < 10) s / dummy; else diff --git a/uppsrc/CtrlLib/HeaderCtrl.cpp b/uppsrc/CtrlLib/HeaderCtrl.cpp index 40563e4d0..0457baf08 100644 --- a/uppsrc/CtrlLib/HeaderCtrl.cpp +++ b/uppsrc/CtrlLib/HeaderCtrl.cpp @@ -707,7 +707,7 @@ void HeaderCtrl::Serialize(Stream& s) { s / n; for(int i = 0; i < n; i++) if(i < col.GetCount()) { - int n; + int n = 1; s / n; col[i].ratio = n; } diff --git a/uppsrc/CtrlLib/LabelBase.cpp b/uppsrc/CtrlLib/LabelBase.cpp index 6d3cef452..b497bf15b 100644 --- a/uppsrc/CtrlLib/LabelBase.cpp +++ b/uppsrc/CtrlLib/LabelBase.cpp @@ -207,7 +207,7 @@ Size DrawLabel::Paint(Ctrl *ctrl, Draw& w, const Rect& r, bool visibleaccesskey) } } Size isz = GetSize(txtcx, sz1, lspc, sz2, rspc); - Point p, ip; + Point p = r.TopLeft(), ip; if(align == ALIGN_LEFT) p.x = r.left; else diff --git a/uppsrc/CtrlLib/PrinterJob.cpp b/uppsrc/CtrlLib/PrinterJob.cpp index 44e3e73b5..c4d95582d 100644 --- a/uppsrc/CtrlLib/PrinterJob.cpp +++ b/uppsrc/CtrlLib/PrinterJob.cpp @@ -151,8 +151,9 @@ String System(const char *cmd, const String& in) c << " >" << ofn; if(in.GetCount()) c << " <" << ifn; - system(c); - String q = LoadFile(ofn); + String q; + if(system(c) >= 0) + q = LoadFile(ofn); FileDelete(ofn); FileDelete(ifn); return q; diff --git a/uppsrc/CtrlLib/ToolButton.cpp b/uppsrc/CtrlLib/ToolButton.cpp index dd5fee09e..05125ade2 100644 --- a/uppsrc/CtrlLib/ToolButton.cpp +++ b/uppsrc/CtrlLib/ToolButton.cpp @@ -224,7 +224,7 @@ void ToolButton::Paint(Draw& w) ChPaint(w, sz, style->look[li]); Point off = style->offset[li]; Point ip = (sz - isz) / 2 + off; - Size tsz; + Size tsz(0, 0); if(kind != NOLABEL) tsz = GetTextSize(text, style->font); if(kind == BOTTOMLABEL) { diff --git a/uppsrc/CtrlLib/TreeCtrl.cpp b/uppsrc/CtrlLib/TreeCtrl.cpp index 5fad33b82..e665ef1a4 100644 --- a/uppsrc/CtrlLib/TreeCtrl.cpp +++ b/uppsrc/CtrlLib/TreeCtrl.cpp @@ -968,7 +968,7 @@ void TreeCtrl::Paint(Draw& w) } } } - Rect dri; + Rect dri = Null; for(int i = FindLine(org.y); i < line.GetCount(); i++) { Line& l = line[i]; const Item& m = item[l.itemi]; diff --git a/uppsrc/Draw/Image.cpp b/uppsrc/Draw/Image.cpp index 92a3c330a..8850e7be3 100644 --- a/uppsrc/Draw/Image.cpp +++ b/uppsrc/Draw/Image.cpp @@ -1,735 +1,735 @@ -#include "Draw.h" - -NAMESPACE_UPP - -#define LTIMING(x) // RTIMING(x) - -int ImageBuffer::ScanKind() const -{ - bool a255 = false; - bool a0 = false; - const RGBA *s = pixels; - const RGBA *e = s + GetLength(); - while(s < e) { - if(s->a == 0) - a0 = true; - else - if(s->a == 255) - a255 = true; - else - return IMAGE_ALPHA; - s++; - } - return a255 ? a0 ? IMAGE_MASK : IMAGE_OPAQUE : IMAGE_EMPTY; -} - -void ImageBuffer::SetHotSpots(const Image& src) -{ - SetHotSpot(src.GetHotSpot()); - Set2ndSpot(src.Get2ndSpot()); -} - -void ImageBuffer::Create(int cx, int cy) -{ - ASSERT(cx >= 0 && cy >= 0); - size.cx = cx; - size.cy = cy; - pixels.Alloc(GetLength()); -#ifdef _DEBUG - RGBA *s = pixels; - RGBA *e = pixels + GetLength(); - byte a = 0; - while(s < e) { - s->a = a; - a = ~a; - s->r = 255; - s->g = s->b = 0; - s++; - } -#endif - kind = IMAGE_UNKNOWN; - spot2 = hotspot = Point(0, 0); - dots = Size(0, 0); -} - -void ImageBuffer::DeepCopy(const ImageBuffer& img) -{ - Create(img.GetSize()); - SetHotSpot(img.GetHotSpot()); - Set2ndSpot(img.Get2ndSpot()); - SetDots(img.GetDots()); - memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); -} - -void ImageBuffer::Set(Image& img) -{ - if(img.data) - if(img.data->refcount == 1) { - size = img.GetSize(); - kind = IMAGE_UNKNOWN; - hotspot = img.GetHotSpot(); - spot2 = img.Get2ndSpot(); - dots = img.GetDots(); - pixels = img.data->buffer.pixels; - img.Clear(); - } - else { - DeepCopy(img.data->buffer); - kind = IMAGE_UNKNOWN; - img.Clear(); - } - else - Create(0, 0); -} - - -void ImageBuffer::operator=(Image& img) -{ - Clear(); - Set(img); -} - -void ImageBuffer::operator=(ImageBuffer& img) -{ - Clear(); - Image m = img; - Set(m); -} - -ImageBuffer::ImageBuffer(Image& img) -{ - Set(img); -} - -ImageBuffer::ImageBuffer(ImageBuffer& b) -{ - kind = b.kind; - size = b.size; - dots = b.dots; - pixels = b.pixels; - hotspot = b.hotspot; - spot2 = b.spot2; -} - -void ImageBuffer::SetDPI(Size dpi) -{ - dots.cx = int(600.*size.cx/dpi.cx); - dots.cy = int(600.*size.cy/dpi.cy); -} - -Size ImageBuffer::GetDPI() -{ - return Size(dots.cx ? int(600.*size.cx/dots.cx) : 0, dots.cy ? int(600.*size.cy/dots.cy) : 0); -} - -void (Image::Data::*Image::Data::sSysInit)(); -void (Image::Data::*Image::Data::sSysRelease)(); -int (Image::Data::*Image::Data::sGetResCount)() const; -void (Image::Data::*Image::Data::sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c); - -void Image::Data::InitSystemImage( - void (Image::Data::*fSysInit)(), - void (Image::Data::*fSysRelease)(), - int (Image::Data::*fGetResCount)() const, - void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c) -) -{ - Image::Data::sSysInit = fSysInit; - Image::Data::sSysRelease = fSysRelease; - Image::Data::sGetResCount = fGetResCount; - Image::Data::sPaint = fPaint; -} - -void Image::Data::SysInit() -{ - if(sSysInit) - (this->*sSysInit)(); -} - -void Image::Data::SysRelease() -{ - if(sSysRelease) - (this->*sSysRelease)(); -} - -int Image::Data::GetResCount() const -{ - if(sGetResCount) - return (this->*sGetResCount)(); - return 0; -} - -void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) -{ - if(sPaint) - (this->*sPaint)(w, x, y, src, c); -} - -void Image::Set(ImageBuffer& b) -{ - if(b.GetWidth() == 0 || b.GetHeight() == 0) - data = NULL; - else - data = new Data(b); -} - -void Image::Clear() -{ - if(data) - data->Release(); - data = NULL; -} - -Image& Image::operator=(ImageBuffer& img) -{ - if(data) - data->Release(); - Set(img); - return *this; -} - -Image& Image::operator=(const Image& img) -{ - Data *d = data; - data = img.data; - if(data) - data->Retain(); - if(d) - d->Release(); - return *this; -} - -const RGBA* Image::operator~() const -{ - return data ? ~data->buffer : NULL; -} - -Image::operator const RGBA*() const -{ - return data ? ~data->buffer : NULL; -} - -const RGBA* Image::operator[](int i) const -{ - ASSERT(data); - return data->buffer[i]; -} - -Size Image::GetSize() const -{ - return data ? data->buffer.GetSize() : Size(0, 0); -} - -int Image::GetLength() const -{ - return data ? data->buffer.GetLength() : 0; -} - -Point Image::GetHotSpot() const -{ - return data ? data->buffer.GetHotSpot() : Point(0, 0); -} - -Point Image::Get2ndSpot() const -{ - return data ? data->buffer.Get2ndSpot() : Point(0, 0); -} - -Size Image::GetDots() const -{ - return data ? data->buffer.GetDots() : Size(0, 0); -} - -Size Image::GetDPI() -{ - Size size = GetSize(); - Size dots = GetDots(); - return data ? Size(int(600.*size.cx/dots.cx), int(600.*size.cy/dots.cy)): Size(0, 0); -} - -int Image::GetKindNoScan() const -{ - return data ? data->buffer.GetKind() : IMAGE_EMPTY; -} - -int Image::Data::GetKind() -{ - int k = buffer.GetKind(); - if(k != IMAGE_UNKNOWN) - return k; - k = buffer.ScanKind(); - buffer.SetKind(k); - return k; -} - -int Image::GetKind() const -{ - return data ? data->GetKind() : IMAGE_EMPTY; -} - -void Image::PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const -{ - if(data) - data->Paint(w, x, y, src, c); -} - -void Image::Serialize(Stream& s) -{ - int version = 0; - s / version; - Size sz = GetSize(); - Point p = GetHotSpot(); - Size dots = GetDots(); - s % sz % p % dots; - int len = sz.cx * sz.cy; - if(s.IsLoading()) - if(len) { - ImageBuffer b(sz); - if(!s.GetAll(~b, len * sizeof(RGBA))) - s.SetError(); - b.SetDots(dots); - b.SetHotSpot(p); - *this = b; - } - else - Clear(); - else - s.Put(~*this, len * sizeof(RGBA)); -} - -INITBLOCK { - RichValue::Register(); -} - -bool Image::operator==(const Image& img) const -{ - if(GetLength() != img.GetLength()) - return false; - return memcmp(~*this, ~img, GetLength() * sizeof(RGBA)) == 0; -} - -bool Image::operator!=(const Image& img) const -{ - return !operator==(img); -} - -dword Image::GetHashValue() const -{ - return memhash(~*this, GetLength() * sizeof(RGBA)); -} - -Image::Image(const Image& img) -{ - data = img.data; - if(data) - data->Retain(); -} - -Image::Image(Image (*fn)()) -{ - data = NULL; - *this = (*fn)(); -} - -Image::Image(const Value& src) -{ - data = NULL; - if(!IsNull(src)) - *this = RawValue::Extract(src); -} - -Image::Image(ImageBuffer& b) -{ - Set(b); -} - -Image::~Image() -{ - if(data) - data->Release(); -} - -Image::Image(const Init& init) -{ - ASSERT(init.info[0] >= 1); - Size sz; - sz.cx = Peek32le(init.info + 1); - sz.cy = Peek32le(init.info + 5); - ImageBuffer b(sz); - int i = 0; - while(i < init.scan_count) { - UnpackRLE(b[i], (const byte *)init.scans[i], sz.cx); - i++; - } - while(i < sz.cy) - memset(b[i++], 0, sizeof(RGBA) * sz.cx); - b.SetHotSpot(Point(Peek32le(init.info + 9), Peek32le(init.info + 13))); - Set(b); -} - -String Image::ToString() const -{ - return String("Image ").Cat() << GetSize(); -} - -Link Image::Data::ResData[1]; -int Image::Data::ResCount; - -Image::Data::Data(ImageBuffer& b) -: buffer(b) -{ - paintcount = 0; - paintonly = false; - refcount = 1; - INTERLOCKED { - static int64 gserial; - serial = ++gserial; - } - SysInit(); -} - -Image::Data::~Data() -{ - DrawLock __; - SysRelease(); - Unlink(); -} - -void Image::Data::PaintOnlyShrink() -{ - if(paintonly) { - LTIMING("PaintOnlyShrink"); - DrawLock __; - DropPixels___(buffer); - ResCount -= GetResCount(); - Unlink(); - } -} - -static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len)) -{ - if(b.GetKind() != IMAGE_OPAQUE && b.GetKind() != IMAGE_EMPTY) - (*op)(~b, ~b, b.GetLength()); -} - -void Premultiply(ImageBuffer& b) -{ - sMultiply(b, Premultiply); -} - -void Unmultiply(ImageBuffer& b) -{ - sMultiply(b, Unmultiply); -} - -static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int len)) -{ - int k = img.GetKind(); - if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) - return img; - ImageBuffer ib(img.GetSize()); - ib.SetHotSpot(img.GetHotSpot()); - ib.Set2ndSpot(img.Get2ndSpot()); - ib.SetKind(Premultiply(~ib, ~img, ib.GetLength())); - return ib; -} - -Image Premultiply(const Image& img) -{ - return sMultiply(img, Premultiply); -} - -Image Unmultiply(const Image& img) -{ - return sMultiply(img, Unmultiply); -} - -void SetPaintOnly___(Image& m) -{ - if(m.data && m.data->refcount == 1) - m.data->paintonly = true; -} - -void Iml::Init(int n) -{ - for(int i = 0; i < n; i++) - map.Add(name[i]); -} - -void Iml::Reset() -{ - int n = map.GetCount(); - map.Clear(); - Init(n); -} - -void Iml::Set(int i, const Image& img) -{ - map[i].image = img; - map[i].loaded = true; -} - -Image Iml::Get(int i) -{ - IImage& m = map[i]; - if(!m.loaded) { - DrawLock __; - if(data.GetCount()) { - int ii = 0; - for(;;) { - const Data& d = data[ii]; - if(i < d.count) { - static const char *cached_data; - static Vector cached; - if(cached_data != d.data) { - cached_data = d.data; - cached = UnpackImlData(String(d.data, d.len)); - if(premultiply) - for(int i = 0; i < cached.GetCount(); i++) - cached[i] = Premultiply(cached[i]); - } - m.image = cached[i]; - break; - } - i -= d.count; - ii++; - } - } - else - m.image = Premultiply(Image(img_init[i])); - m.loaded = true; - } - return m.image; -} - -#ifdef _DEBUG -int Iml::GetBinSize() const -{ - int size = 0; - for(int i = 0; i < map.GetCount(); i++) { - const Image::Init& init = img_init[i]; - size += (int)strlen(name[i]) + 1 + 24; - for(int q = 0; q < init.scan_count; q++) - size += (int)strlen(init.scans[q]); - } - return size; -} -#endif - -Iml::Iml(const Image::Init *img_init, const char **name, int n) -: img_init(img_init), - name(name) -{ -#ifdef flagCHECKINIT - RLOG("Constructing iml " << *name); -#endif - premultiply = true; - Init(n); -} - -void Iml::AddData(const byte *_data, int len, int count) -{ - Data& d = data.Add(); - d.data = (const char *)_data; - d.len = len; - d.count = count; - data.Shrink(); -} - -static StaticCriticalSection sImgMapLock; - -static VectorMap& sImgMap() -{ - static VectorMap x; - return x; -} - -void Register(const char *imageclass, Iml& list) -{ -#ifdef flagCHECKINIT - RLOG("Registering iml " << imageclass); -#endif - INTERLOCKED_(sImgMapLock) - sImgMap().GetAdd(imageclass) = &list; -} - -int GetImlCount() -{ - int q; - INTERLOCKED_(sImgMapLock) - q = sImgMap().GetCount(); - return q; -} - -Iml& GetIml(int i) -{ - return *sImgMap()[i]; -} - -String GetImlName(int i) -{ - DrawLock __; - return sImgMap().GetKey(i); -} - -int FindIml(const char *name) -{ - DrawLock __; - return sImgMap().Find(name); -} - -Image GetImlImage(const char *name) -{ - Image m; - const char *w = strchr(name, ':'); - if(w) { - DrawLock __; - int q = FindIml(String(name, w)); - if(q >= 0) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - m = iml.Get(q); - } - } - return m; -} - -void SetImlImage(const char *name, const Image& m) -{ - const char *w = strchr(name, ':'); - if(w) { - DrawLock __; - int q = FindIml(String(name, w)); - if(q >= 0) { - Iml& iml = *sImgMap()[q]; - while(*w == ':') - w++; - q = iml.Find(w); - if(q >= 0) - iml.Set(q, m); - } - } -} - -String StoreImageAsString(const Image& img) -{ - if(img.GetKind() == IMAGE_EMPTY) - return Null; - int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; - StringStream ss; - ss.Put(type); - Size sz = img.GetSize(); - ss.Put16le(sz.cx); - ss.Put16le(sz.cy); - Point p = img.GetHotSpot(); - ss.Put16le(p.x); - ss.Put16le(p.y); - Size dots = img.GetDots(); - ss.Put16le(dots.cx); - ss.Put16le(dots.cy); - const RGBA *s = img; - const RGBA *e = s + img.GetLength(); - Buffer b(type * img.GetLength()); - byte *t = b; - if(type == 3) - while(s < e) { - *t++ = s->r; - *t++ = s->g; - *t++ = s->b; - s++; - } - else - while(s < e) { - *t++ = s->r; - *t++ = s->g; - *t++ = s->b; - *t++ = s->a; - s++; - } - MemReadStream m(b, type * img.GetLength()); - ZCompress(ss, m); - return ss; -} - -Image LoadImageFromString(const String& src) -{ - if(src.GetLength() < 13) - return Null; - StringStream ss(src); - int type = ss.Get(); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - if(sz.cx < 0 || sz.cy < 0) - return Null; - Point p; - p.x = ss.Get16le(); - p.y = ss.Get16le(); - if(p.x < 0 || p.y < 0) - return Null; - Size dots; - dots.cx = ss.Get16le(); - dots.cy = ss.Get16le(); - if(dots.cx < 0 || dots.cy < 0) - return Null; - StringStream out; - ZDecompress(out, ss); - String data = out; - if(data.GetLength() != type * sz.cx * sz.cy) - return Image(); - ImageBuffer ib(sz); - ib.SetHotSpot(p); - ib.SetDots(dots); - RGBA *t = ib; - const RGBA *e = t + ib.GetLength(); - const byte *s = data; - if(type == 3) - while(t < e) { - t->r = *s++; - t->g = *s++; - t->b = *s++; - t->a = 255; - t++; - } - else - if(type == 4) - while(t < e) { - t->r = *s++; - t->g = *s++; - t->b = *s++; - t->a = *s++; - t++; - } - else - return Image(); - return ib; -} - -Size GetImageStringSize(const String& src) -{ - if(src.GetLength() < 13) - return Size(0, 0); - StringStream ss(src); - ss.Get(); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - return sz; -} - -Size GetImageStringDots(const String& src) -{ - if(src.GetLength() < 13) - return Size(0, 0); - StringStream ss(src); - ss.SeekCur(9); - Size sz; - sz.cx = ss.Get16le(); - sz.cy = ss.Get16le(); - return sz; -} - -END_UPP_NAMESPACE +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +int ImageBuffer::ScanKind() const +{ + bool a255 = false; + bool a0 = false; + const RGBA *s = pixels; + const RGBA *e = s + GetLength(); + while(s < e) { + if(s->a == 0) + a0 = true; + else + if(s->a == 255) + a255 = true; + else + return IMAGE_ALPHA; + s++; + } + return a255 ? a0 ? IMAGE_MASK : IMAGE_OPAQUE : IMAGE_EMPTY; +} + +void ImageBuffer::SetHotSpots(const Image& src) +{ + SetHotSpot(src.GetHotSpot()); + Set2ndSpot(src.Get2ndSpot()); +} + +void ImageBuffer::Create(int cx, int cy) +{ + ASSERT(cx >= 0 && cy >= 0); + size.cx = cx; + size.cy = cy; + pixels.Alloc(GetLength()); +#ifdef _DEBUG + RGBA *s = pixels; + RGBA *e = pixels + GetLength(); + byte a = 0; + while(s < e) { + s->a = a; + a = ~a; + s->r = 255; + s->g = s->b = 0; + s++; + } +#endif + kind = IMAGE_UNKNOWN; + spot2 = hotspot = Point(0, 0); + dots = Size(0, 0); +} + +void ImageBuffer::DeepCopy(const ImageBuffer& img) +{ + Create(img.GetSize()); + SetHotSpot(img.GetHotSpot()); + Set2ndSpot(img.Get2ndSpot()); + SetDots(img.GetDots()); + memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); +} + +void ImageBuffer::Set(Image& img) +{ + if(img.data) + if(img.data->refcount == 1) { + size = img.GetSize(); + kind = IMAGE_UNKNOWN; + hotspot = img.GetHotSpot(); + spot2 = img.Get2ndSpot(); + dots = img.GetDots(); + pixels = img.data->buffer.pixels; + img.Clear(); + } + else { + DeepCopy(img.data->buffer); + kind = IMAGE_UNKNOWN; + img.Clear(); + } + else + Create(0, 0); +} + + +void ImageBuffer::operator=(Image& img) +{ + Clear(); + Set(img); +} + +void ImageBuffer::operator=(ImageBuffer& img) +{ + Clear(); + Image m = img; + Set(m); +} + +ImageBuffer::ImageBuffer(Image& img) +{ + Set(img); +} + +ImageBuffer::ImageBuffer(ImageBuffer& b) +{ + kind = b.kind; + size = b.size; + dots = b.dots; + pixels = b.pixels; + hotspot = b.hotspot; + spot2 = b.spot2; +} + +void ImageBuffer::SetDPI(Size dpi) +{ + dots.cx = int(600.*size.cx/dpi.cx); + dots.cy = int(600.*size.cy/dpi.cy); +} + +Size ImageBuffer::GetDPI() +{ + return Size(dots.cx ? int(600.*size.cx/dots.cx) : 0, dots.cy ? int(600.*size.cy/dots.cy) : 0); +} + +void (Image::Data::*Image::Data::sSysInit)(); +void (Image::Data::*Image::Data::sSysRelease)(); +int (Image::Data::*Image::Data::sGetResCount)() const; +void (Image::Data::*Image::Data::sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c); + +void Image::Data::InitSystemImage( + void (Image::Data::*fSysInit)(), + void (Image::Data::*fSysRelease)(), + int (Image::Data::*fGetResCount)() const, + void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c) +) +{ + Image::Data::sSysInit = fSysInit; + Image::Data::sSysRelease = fSysRelease; + Image::Data::sGetResCount = fGetResCount; + Image::Data::sPaint = fPaint; +} + +void Image::Data::SysInit() +{ + if(sSysInit) + (this->*sSysInit)(); +} + +void Image::Data::SysRelease() +{ + if(sSysRelease) + (this->*sSysRelease)(); +} + +int Image::Data::GetResCount() const +{ + if(sGetResCount) + return (this->*sGetResCount)(); + return 0; +} + +void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) +{ + if(sPaint) + (this->*sPaint)(w, x, y, src, c); +} + +void Image::Set(ImageBuffer& b) +{ + if(b.GetWidth() == 0 || b.GetHeight() == 0) + data = NULL; + else + data = new Data(b); +} + +void Image::Clear() +{ + if(data) + data->Release(); + data = NULL; +} + +Image& Image::operator=(ImageBuffer& img) +{ + if(data) + data->Release(); + Set(img); + return *this; +} + +Image& Image::operator=(const Image& img) +{ + Data *d = data; + data = img.data; + if(data) + data->Retain(); + if(d) + d->Release(); + return *this; +} + +const RGBA* Image::operator~() const +{ + return data ? ~data->buffer : NULL; +} + +Image::operator const RGBA*() const +{ + return data ? ~data->buffer : NULL; +} + +const RGBA* Image::operator[](int i) const +{ + ASSERT(data); + return data->buffer[i]; +} + +Size Image::GetSize() const +{ + return data ? data->buffer.GetSize() : Size(0, 0); +} + +int Image::GetLength() const +{ + return data ? data->buffer.GetLength() : 0; +} + +Point Image::GetHotSpot() const +{ + return data ? data->buffer.GetHotSpot() : Point(0, 0); +} + +Point Image::Get2ndSpot() const +{ + return data ? data->buffer.Get2ndSpot() : Point(0, 0); +} + +Size Image::GetDots() const +{ + return data ? data->buffer.GetDots() : Size(0, 0); +} + +Size Image::GetDPI() +{ + Size size = GetSize(); + Size dots = GetDots(); + return data ? Size(int(600.*size.cx/dots.cx), int(600.*size.cy/dots.cy)): Size(0, 0); +} + +int Image::GetKindNoScan() const +{ + return data ? data->buffer.GetKind() : IMAGE_EMPTY; +} + +int Image::Data::GetKind() +{ + int k = buffer.GetKind(); + if(k != IMAGE_UNKNOWN) + return k; + k = buffer.ScanKind(); + buffer.SetKind(k); + return k; +} + +int Image::GetKind() const +{ + return data ? data->GetKind() : IMAGE_EMPTY; +} + +void Image::PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const +{ + if(data) + data->Paint(w, x, y, src, c); +} + +void Image::Serialize(Stream& s) +{ + int version = 0; + s / version; + Size sz = GetSize(); + Point p = GetHotSpot(); + Size dots = GetDots(); + s % sz % p % dots; + int len = sz.cx * sz.cy; + if(s.IsLoading()) + if(len) { + ImageBuffer b(sz); + if(!s.GetAll(~b, len * sizeof(RGBA))) + s.SetError(); + b.SetDots(dots); + b.SetHotSpot(p); + *this = b; + } + else + Clear(); + else + s.Put(~*this, len * sizeof(RGBA)); +} + +INITBLOCK { + RichValue::Register(); +} + +bool Image::operator==(const Image& img) const +{ + if(GetLength() != img.GetLength()) + return false; + return memcmp(~*this, ~img, GetLength() * sizeof(RGBA)) == 0; +} + +bool Image::operator!=(const Image& img) const +{ + return !operator==(img); +} + +dword Image::GetHashValue() const +{ + return memhash(~*this, GetLength() * sizeof(RGBA)); +} + +Image::Image(const Image& img) +{ + data = img.data; + if(data) + data->Retain(); +} + +Image::Image(Image (*fn)()) +{ + data = NULL; + *this = (*fn)(); +} + +Image::Image(const Value& src) +{ + data = NULL; + if(!IsNull(src)) + *this = RawValue::Extract(src); +} + +Image::Image(ImageBuffer& b) +{ + Set(b); +} + +Image::~Image() +{ + if(data) + data->Release(); +} + +Image::Image(const Init& init) +{ + ASSERT(init.info[0] >= 1); + Size sz; + sz.cx = Peek32le(init.info + 1); + sz.cy = Peek32le(init.info + 5); + ImageBuffer b(sz); + int i = 0; + while(i < init.scan_count) { + UnpackRLE(b[i], (const byte *)init.scans[i], sz.cx); + i++; + } + while(i < sz.cy) + memset(b[i++], 0, sizeof(RGBA) * sz.cx); + b.SetHotSpot(Point(Peek32le(init.info + 9), Peek32le(init.info + 13))); + Set(b); +} + +String Image::ToString() const +{ + return String("Image ").Cat() << GetSize(); +} + +Link Image::Data::ResData[1]; +int Image::Data::ResCount; + +Image::Data::Data(ImageBuffer& b) +: buffer(b) +{ + paintcount = 0; + paintonly = false; + refcount = 1; + INTERLOCKED { + static int64 gserial; + serial = ++gserial; + } + SysInit(); +} + +Image::Data::~Data() +{ + DrawLock __; + SysRelease(); + Unlink(); +} + +void Image::Data::PaintOnlyShrink() +{ + if(paintonly) { + LTIMING("PaintOnlyShrink"); + DrawLock __; + DropPixels___(buffer); + ResCount -= GetResCount(); + Unlink(); + } +} + +static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + if(b.GetKind() != IMAGE_OPAQUE && b.GetKind() != IMAGE_EMPTY) + (*op)(~b, ~b, b.GetLength()); +} + +void Premultiply(ImageBuffer& b) +{ + sMultiply(b, Premultiply); +} + +void Unmultiply(ImageBuffer& b) +{ + sMultiply(b, Unmultiply); +} + +static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + int k = img.GetKind(); + if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) + return img; + ImageBuffer ib(img.GetSize()); + ib.SetHotSpot(img.GetHotSpot()); + ib.Set2ndSpot(img.Get2ndSpot()); + ib.SetKind(Premultiply(~ib, ~img, ib.GetLength())); + return ib; +} + +Image Premultiply(const Image& img) +{ + return sMultiply(img, Premultiply); +} + +Image Unmultiply(const Image& img) +{ + return sMultiply(img, Unmultiply); +} + +void SetPaintOnly___(Image& m) +{ + if(m.data && m.data->refcount == 1) + m.data->paintonly = true; +} + +void Iml::Init(int n) +{ + for(int i = 0; i < n; i++) + map.Add(name[i]); +} + +void Iml::Reset() +{ + int n = map.GetCount(); + map.Clear(); + Init(n); +} + +void Iml::Set(int i, const Image& img) +{ + map[i].image = img; + map[i].loaded = true; +} + +Image Iml::Get(int i) +{ + IImage& m = map[i]; + if(!m.loaded) { + DrawLock __; + if(data.GetCount()) { + int ii = 0; + for(;;) { + const Data& d = data[ii]; + if(i < d.count) { + static const char *cached_data; + static Vector cached; + if(cached_data != d.data) { + cached_data = d.data; + cached = UnpackImlData(d.data, d.len); + if(premultiply) + for(int i = 0; i < cached.GetCount(); i++) + cached[i] = Premultiply(cached[i]); + } + m.image = cached[i]; + break; + } + i -= d.count; + ii++; + } + } + else + m.image = Premultiply(Image(img_init[i])); + m.loaded = true; + } + return m.image; +} + +#ifdef _DEBUG +int Iml::GetBinSize() const +{ + int size = 0; + for(int i = 0; i < map.GetCount(); i++) { + const Image::Init& init = img_init[i]; + size += (int)strlen(name[i]) + 1 + 24; + for(int q = 0; q < init.scan_count; q++) + size += (int)strlen(init.scans[q]); + } + return size; +} +#endif + +Iml::Iml(const Image::Init *img_init, const char **name, int n) +: img_init(img_init), + name(name) +{ +#ifdef flagCHECKINIT + RLOG("Constructing iml " << *name); +#endif + premultiply = true; + Init(n); +} + +void Iml::AddData(const byte *_data, int len, int count) +{ + Data& d = data.Add(); + d.data = (const char *)_data; + d.len = len; + d.count = count; + data.Shrink(); +} + +static StaticCriticalSection sImgMapLock; + +static VectorMap& sImgMap() +{ + static VectorMap x; + return x; +} + +void Register(const char *imageclass, Iml& list) +{ +#ifdef flagCHECKINIT + RLOG("Registering iml " << imageclass); +#endif + INTERLOCKED_(sImgMapLock) + sImgMap().GetAdd(imageclass) = &list; +} + +int GetImlCount() +{ + int q; + INTERLOCKED_(sImgMapLock) + q = sImgMap().GetCount(); + return q; +} + +Iml& GetIml(int i) +{ + return *sImgMap()[i]; +} + +String GetImlName(int i) +{ + DrawLock __; + return sImgMap().GetKey(i); +} + +int FindIml(const char *name) +{ + DrawLock __; + return sImgMap().Find(name); +} + +Image GetImlImage(const char *name) +{ + Image m; + const char *w = strchr(name, ':'); + if(w) { + DrawLock __; + int q = FindIml(String(name, w)); + if(q >= 0) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + m = iml.Get(q); + } + } + return m; +} + +void SetImlImage(const char *name, const Image& m) +{ + const char *w = strchr(name, ':'); + if(w) { + DrawLock __; + int q = FindIml(String(name, w)); + if(q >= 0) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + iml.Set(q, m); + } + } +} + +String StoreImageAsString(const Image& img) +{ + if(img.GetKind() == IMAGE_EMPTY) + return Null; + int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; + StringStream ss; + ss.Put(type); + Size sz = img.GetSize(); + ss.Put16le(sz.cx); + ss.Put16le(sz.cy); + Point p = img.GetHotSpot(); + ss.Put16le(p.x); + ss.Put16le(p.y); + Size dots = img.GetDots(); + ss.Put16le(dots.cx); + ss.Put16le(dots.cy); + const RGBA *s = img; + const RGBA *e = s + img.GetLength(); + Buffer b(type * img.GetLength()); + byte *t = b; + if(type == 3) + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + s++; + } + else + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + *t++ = s->a; + s++; + } + MemReadStream m(b, type * img.GetLength()); + ZCompress(ss, m); + return ss; +} + +Image LoadImageFromString(const String& src) +{ + if(src.GetLength() < 13) + return Null; + StringStream ss(src); + int type = ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + if(sz.cx < 0 || sz.cy < 0) + return Null; + Point p; + p.x = ss.Get16le(); + p.y = ss.Get16le(); + if(p.x < 0 || p.y < 0) + return Null; + Size dots; + dots.cx = ss.Get16le(); + dots.cy = ss.Get16le(); + if(dots.cx < 0 || dots.cy < 0) + return Null; + StringStream out; + ZDecompress(out, ss); + String data = out; + if(data.GetLength() != type * sz.cx * sz.cy) + return Image(); + ImageBuffer ib(sz); + ib.SetHotSpot(p); + ib.SetDots(dots); + RGBA *t = ib; + const RGBA *e = t + ib.GetLength(); + const byte *s = data; + if(type == 3) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = 255; + t++; + } + else + if(type == 4) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = *s++; + t++; + } + else + return Image(); + return ib; +} + +Size GetImageStringSize(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +Size GetImageStringDots(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.SeekCur(9); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/ide/Builders/MscBuilder.icpp b/uppsrc/ide/Builders/MscBuilder.icpp index e47a22c1a..cc9fef4f2 100644 --- a/uppsrc/ide/Builders/MscBuilder.icpp +++ b/uppsrc/ide/Builders/MscBuilder.icpp @@ -1,612 +1,612 @@ -#include "Builders.h" - -#include - -#ifdef PLATFORM_WIN32 -static bool HasTail(String s, const char *tail) -{ - int tl = (int)strlen(tail); - int sl = s.GetLength(); - if(sl < tl) - return false; - for(const char *p = s.GetIter(sl - tl); *p; p++, tail++) - if(*tail != '*' && *tail != *p) - return false; - return *tail == 0; -} -#endif - -static void AddObjectExports(const char *path, Index& out) -{ -#ifdef PLATFORM_WIN32 - FileMapping mapping; - if(!mapping.Open(path)) - return; - const byte *begin = mapping.Begin(); - const COFF_IMAGE_FILE_HEADER *hdr = (const COFF_IMAGE_FILE_HEADER *)begin; - if(hdr->Machine != COFF_IMAGE_FILE_MACHINE_I386) - return; - const COFF_IMAGE_SECTION_HEADER *sechdr = (const COFF_IMAGE_SECTION_HEADER *)(begin - + sizeof(COFF_IMAGE_FILE_HEADER) + hdr->SizeOfOptionalHeader); - Index code_sections; - for(int i = 0; i < hdr->NumberOfSections; i++) - if(sechdr[i].Characteristics & COFF_IMAGE_SCN_CNT_CODE) - code_sections.Add(i + 1); - const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + hdr->PointerToSymbolTable); - const char *strtbl = (const char *)(symtbl + hdr->NumberOfSymbols); - for(int i = 0; i < (int)hdr->NumberOfSymbols; i++) - { - const COFF_IMAGE_SYMBOL& sym = symtbl[i]; - if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL && code_sections.Find(sym.SectionNumber) >= 0) - { - String name = COFFSymbolName(sym, strtbl); - if(!HasTail(name, "AEPAXI@Z")) - { - if(*name == '_' && name.Find('@') < 0) - name.Remove(0, 1); - out.FindAdd(name); - } - } - i += sym.NumberOfAuxSymbols; - } -#endif -} - -void MscBuilder::AddFlags(Index& cfg) -{ - cfg.FindAdd("MSC"); -} - -String MscBuilder::CmdLine(const String& package, const Package& pkg) -{ - String cc; - if(HasFlag("ARM")) - cc = "clarm"; - else - if(HasFlag("MIPS")) - cc = "clmips"; - else - if(HasFlag("SH3")) - cc = "shcl /Qsh3"; - else - if(HasFlag("SH4")) - cc = "shcl /Qsh4"; - else - if(HasFlag("MSC8ARM")) - cc = "cl -GS- "; - else - cc = HasFlag("INTEL") ? "icl" : "cl"; -// TRC 080605-documentation says Wp64 works in 32-bit compilation only -// cc << (IsMsc64() ? " -nologo -Wp64 -W3 -GR -c" : " -nologo -W3 -GR -c"); - cc << " -nologo -W3 -GR -c"; - cc << IncludesDefinesTargetTime(package, pkg); - - return cc; -} - -String MscBuilder::MachineName() const -{ - if(HasFlag("ARM")) return "ARM"; - if(HasFlag("MIPS")) return "MIPS"; - if(HasFlag("SH3")) return "SH3"; - if(HasFlag("SH4")) return "SH4"; - if(IsMscArm()) return "ARM"; - if(IsMsc64()) return "x64"; - if(HasFlag("WIN32")) return "I386"; - return "IX86"; -} - -bool MscBuilder::IsMsc89() const -{ - return IsMsc86() || IsMsc64() || IsMscArm(); -} - -bool MscBuilder::IsMsc86() const -{ - return HasFlag("MSC8") || HasFlag("MSC9") || HasFlag("MSC10"); -} - -bool MscBuilder::IsMscArm() const -{ - return HasFlag("MSC8ARM") || HasFlag("MSC9ARM"); -} - -bool MscBuilder::IsMsc64() const -{ - return HasFlag("MSC8X64") || HasFlag("MSC9X64") || HasFlag("MSC10X64"); -} - -String MscBuilder::LinkerName() const -{ - if(HasFlag("ULD")) return "uld"; - if(HasFlag("INTEL")) return "xilink"; - return "link"; -} - -static bool sContainsPchOptions(const String& x) -{ - Index a = Split(x, ' '); - return a.Find("-GL") >= 0 || a.Find("/GL") >= 0 || a.Find("-Y-") >= 0 || a.Find("/Y-") >= 0 - || a.Find("-Yc") >= 0 || a.Find("/Yc") >= 0 || a.Find("-Yd") >= 0 || a.Find("/Yd") >= 0 - || a.Find("-Yl") >= 0 || a.Find("/Yl") >= 0 || a.Find("-Yu") >= 0 || a.Find("/Yu") >= 0 - || a.Find("-YX") >= 0 || a.Find("/YX") >= 0; -} - -bool MscBuilder::HasAnyDebug() const -{ - return HasFlag("DEBUG") || HasFlag("DEBUG_MINIMAL") || HasFlag("DEBUG_FULL"); -} - -String MscBuilder::PdbPch(String package, int slot, bool do_pch) const -{ - String pkg_slot = NFormat("%s-%d", GetAnyFileName(package), slot + 1); - String pdb = GetHostPathQ(CatAnyPath(outdir, pkg_slot + ".pdb")); - String cc; - cc << " -Gy -Fd" << pdb; - if(do_pch && !IsMsc89()) // MSC8/9 does not support automatic precompiled headers... - cc << " -YX -Fp" << GetHostPathQ(CatAnyPath(outdir, pkg_slot + ".pch")) << ' '; - return cc; -} - -bool MscBuilder::BuildPackage(const String& package, Vector& linkfile, String& linkoptions, - const Vector& all_uses, const Vector& all_libraries, int opt) -{ - int i; - String packagepath = PackagePath(package); - Package pkg; - pkg.Load(packagepath); - String packagedir = GetFileFolder(packagepath); - ChDir(packagedir); - PutVerbose("cd " + packagedir); - IdeConsoleBeginGroup(package); - Vector obj; - - bool is_shared = HasFlag("SO"), - is_clr = HasFlag("CLR"); - - String cc = CmdLine(package, pkg); - if(HasFlag("EVC")) { - if(!HasFlag("SH3") && !HasFlag("SH4")) - cc << " -Gs8192"; // disable stack checking - cc << " -GF" // read-only string pooling - " -GX-"; // turn off exception handling - } - else - if(is_clr) - cc << " -EHac"; - else - if(IsMsc89()) - cc << " -EHsc"; - else - cc << " -GX"; -// String pdb = GetHostPathQ(CatAnyPath(outdir, GetAnyFileName(package) + ".pdb")); -// String pch; -// if(!HasFlag("MSC8")) // MSC8 does not support automatic precompiled headers... -// pch << " -YX -Fp" << GetHostPathQ(CatAnyPath(outdir, GetAnyFileName(package) + ".pch")) << ' '; -// cc << " -Gy -Fd" << pdb; - if(HasFlag("SSE2") && !IsMsc64()) - cc << " /arch:SSE2"; - if(HasFlag("DEBUG_MINIMAL")) - cc << " -Zd"; - if(HasFlag("DEBUG_FULL")) - cc << " -Zi"; - cc << ' ' << Gather(pkg.option, config.GetKeys()); - cc << (HasFlag("SHARED") || is_shared || is_clr ? " -MD" - : (HasFlag("MT") || IsMsc89()) ? " -MT" : " -ML"); - - String cc_size = cc; - String cc_speed = cc; - bool release = false; - - if(HasFlag("DEBUG")) - cc << "d " << debug_options; - else { - release = true; - cc << ' ' << release_size_options; - cc_speed << ' ' << release_options; - if(opt == R_SPEED || pkg.optimize_speed) - cc = cc_speed; - } - - - Vector sfile, isfile; - Vector soptions, isoptions; - Vector optimize, ioptimize; - Vector sobjfile; - bool error = false; - - for(i = 0; i < pkg.GetCount(); i++) { - if(!IdeIsBuilding()) - return false; - if(!pkg[i].separator) { - String gop = Gather(pkg[i].option, config.GetKeys()); - Vector srcfile = CustomStep(pkg[i], package, error); - if(srcfile.GetCount() == 0) - error = true; - for(int j = 0; j < srcfile.GetCount(); j++) { - String fn = srcfile[j]; - String ext = ToLower(GetFileExt(fn)); - if(ext == ".c" || ext == ".cpp" || ext == ".cc" || ext == ".cxx" || ext == ".rc" || ext == ".brc") { - sfile.Add(fn); - soptions.Add(gop); - optimize.Add(release && pkg[i].optimize_speed && opt == R_OPTIMAL); - } - else - if(ext == ".icpp") { - isfile.Add(fn); - isoptions.Add(gop); - ioptimize.Add(release && pkg[i].optimize_speed && opt == R_OPTIMAL); - } - else - if(ext == ".obj") - obj.Add(fn); - else - if(ext == ".lib") - linkfile.Add(fn); - } - } - } - - if(HasFlag("BLITZ")) { - Blitz b = BlitzStep(sfile, soptions, obj, ".obj", optimize); - if(b.build) { - PutConsole("BLITZ:" + b.info); - int slot = AllocSlot(); - if(slot < 0 || ! Run(cc + PdbPch(package, slot, false) - + " -Tp " + GetHostPathQ(b.path) + " -Fo" + GetHostPathQ(b.object), slot, GetHostPath(b.object), b.count)) - error = true; - } - } - - int first_ifile = sfile.GetCount(); - sfile.AppendPick(isfile); - soptions.AppendPick(isoptions); - optimize.AppendPick(ioptimize); - - int ccount = 0; - -// if(sContainsPchOptions(cc)) -// pch = Null; - - for(i = 0; i < sfile.GetCount(); i++) { - if(!IdeIsBuilding()) - return false; - String fn = sfile[i]; - String ext = ToLower(GetFileExt(fn)); - bool rc = (ext == ".rc"); - bool brc = (ext == ".brc"); - bool init = (i >= first_ifile); - String objfile = CatAnyPath(outdir, GetFileTitle(fn) + (rc ? "$rc.obj" : brc ? "$brc.obj" : ".obj")); - if(HdependFileTime(fn) > GetFileTime(objfile)) { - int time = GetTickCount(); - bool execerr = false; - if(rc) { - PutConsole(GetFileNamePos(fn)); - int slot = AllocSlot(); - if(slot < 0 || !Run("rc /fo" + GetHostPathQ(objfile) + Includes(" /i", package, pkg) - + ' ' + GetHostPathQ(fn), slot, GetHostPath(objfile), 1)) - execerr = true; - } - else - if(brc) { - try { -// String hfn = GetHostPath(fn); - String brcdata = LoadFile(fn); - if(brcdata.IsVoid()) - throw Exc(NFormat("error reading file '%s'", fn)); - CParser parser(brcdata, fn); - String fo = BrcToC(GetHostPath(objfile), parser, GetFileDirectory(fn), package, pkg); - String tmpfile = ForceExt(objfile, ".c"); - SaveFile(tmpfile, fo); - int slot = AllocSlot(); - if(slot < 0 || !Run(cc + " -Tc " + GetHostPathQ(tmpfile) + " -Fo" + GetHostPath(objfile), - slot, GetHostPath(objfile), 1)) - throw Exc(NFormat("Error compiling binary object '%s'.", objfile)); - } - catch(Exc e) { - PutConsole(e); - execerr = true; - } - } - else { - String c = cc; - if(optimize[i]) - c = cc_speed; - int slot = AllocSlot(); - if(slot < 0 || !Run(c + PdbPch(package, slot, !sContainsPchOptions(cc) && !sContainsPchOptions(soptions[i])) - + " " + soptions[i] + (ext == ".c" ? " -Tc " : " -Tp ") - + GetHostPathQ(fn) + " -Fo" + GetHostPathQ(objfile), slot, GetHostPath(objfile), 1)) - execerr = true; - } - if(execerr) - DeleteFile(objfile); - error |= execerr; - PutVerbose("compiled in " + GetPrintTime(time)); - ccount++; - } - if(init) - linkfile.Add(objfile); - else - obj.Add(objfile); - } - if(error) { -// ShowTime(ccount, time); - IdeConsoleEndGroup(); - return false; - } - - Vector pkglibs = Split(Gather(pkg.library, config.GetKeys()), ' '); - for(int i = 0; i < pkglibs.GetCount(); i++) { - String libfile = AppendExt(pkglibs[i], ".lib"); - if(!IsFullPath(libfile)) { - for(int p = 0; p < libpath.GetCount(); p++) { - String nf = NormalizePath(libfile, libpath[p]); - if(FileExists(nf)) { - libfile = nf; - break; - } - } - } - linkfile.Add(libfile); - } - linkoptions << ' ' << Gather(pkg.link, config.GetKeys()); - - int linktime = GetTickCount(); - if(!HasFlag("MAIN")) { - if(HasFlag("BLITZ") || HasFlag("NOLIB")) { - linkfile.Append(obj); -// ShowTime(ccount, time); - IdeConsoleEndGroup(); - return true; - } - String product; - if(is_shared) - product = GetSharedLibPath(package); - else - product = CatAnyPath(outdir, GetAnyFileName(package) + ".lib"); - Time producttime = GetFileTime(product); - linkfile.Add(ForceExt(product, ".lib")); - if(!Wait()) { - IdeConsoleEndGroup(); - return false; - } - Vector objinfo = host->GetFileInfo(obj); - for(int i = 0; i < obj.GetCount(); i++) - if(objinfo[i] > producttime) { - String linker, lib; - if(is_shared) { - linker << LinkerName() << "-dll -nologo "; - lib << "-machine:" << MachineName() - << " -pdb:" << GetHostPathQ(ForceExt(product, ".pdb")) - << " -out:" << GetHostPathQ(product); - if(!HasFlag("MSC10") && !HasFlag("MSC10X64")) - lib << " -incremental:no"; - if(HasFlag("FORCE_SIZE")){ - if(sContainsPchOptions(release_size_options)) - lib << " -ltcg"; - } - else - if(HasFlag("FORCE_SPEED")) - if(sContainsPchOptions(release_options)) - lib << " -ltcg"; - if(HasAnyDebug()) - lib << " -debug -OPT:NOREF"; - else - lib << " -release -OPT:REF,ICF"; - if(IsMscArm()) - lib << " -subsystem:windowsce,4.20 /ARMPADCODE"; - else - if(HasFlag("GUI")) - lib << (HasFlag("WIN32") ? " -subsystem:windows" - : " -subsystem:windowsce"); - else - lib << " -subsystem:console"; - Index exports; - for(int o = 0; o < obj.GetCount(); o++) - AddObjectExports(obj[o], exports); - String def; - def << "LIBRARY " << AsCString(GetFileName(product)) << "\n\n" - "EXPORTS\n"; - for(int o = 0; o < exports.GetCount(); o++) - def << '\t' << exports[o] << "\n"; //" @" << (o + 1) << "\n"; - String deffile = ForceExt(product, ".def"); - if(!SaveChangedFile(deffile, def)) - { - PutConsole(NFormat("%s: error saving file", deffile)); - return false; - } - lib << " -def:" << GetHostPathQ(deffile); - for(int i = 0; i < libpath.GetCount(); i++) - lib << " -LIBPATH:" << GetHostPathQ(libpath[i]); - lib << ' ' << Gather(pkg.link, config.GetKeys()); - for(int i = 0; i < all_uses.GetCount(); i++) - lib << ' ' << GetHostPathQ(ForceExt(GetSharedLibPath(all_uses[i]), ".lib")); - for(int i = 0; i < all_libraries.GetCount(); i++) { - String libfile = AppendExt(all_libraries[i], ".lib"); - if(!IsFullPath(libfile)) { - for(int p = 0; p < libpath.GetCount(); p++) { - String nf = NormalizePath(libfile, libpath[p]); - if(FileExists(nf)) { - libfile = nf; - break; - } - } - } - lib << ' ' << GetHostPathQ(libfile); - } - } - else{ - linker << (HasFlag("INTEL") ? "xilib" : "link /lib") << " -nologo "; - if(HasFlag("FORCE_SIZE")){ - if(sContainsPchOptions(release_size_options)) - lib << " -ltcg"; - } - else - if(HasFlag("FORCE_SPEED")) - if(sContainsPchOptions(release_options)) - lib << " -ltcg"; - lib << " -out:" << GetHostPathQ(product) << ' ' << Gather(pkg.link, config.GetKeys()); - } - for(int i = 0; i < obj.GetCount(); i++) - lib << ' ' << GetHostPathQ(obj[i]); - PutConsole("Creating library..."); - IdeConsoleEndGroup(); - DeleteFile(product); - String tmpFileName; - if(linker.GetCount() + lib.GetCount() >= 8192) - { - tmpFileName = GetTempFileName(); - // we can't simply put all data on a single line - // as it has a limit of around 130000 chars too, so we split - // in multiple lines - FileOut f(tmpFileName); - while(lib != "") - { - int found = 0; - bool quotes = false; - int lim = min(8192, lib.GetCount()); - for(int i = 0; i < lim; i++) - { - char c = lib[i]; - if(isspace(c) && !quotes) - found = i; - else if(c == '"') - quotes = !quotes; - } - if(!found) - found = lib.GetCount(); - f.PutLine(lib.Left(found)); - lib.Remove(0, found); - } - f.Close(); - linker << "@" << tmpFileName; - } - else - linker << lib; - bool res = Execute(linker); - if(tmpFileName != "") - FileDelete(tmpFileName); - if(res) { - DeleteFile(product); - return false; - } - else - if((IsMsc86() || IsMsc64()) && is_shared) { - String mt("mt -nologo -manifest "); - mt << GetHostPathQ(product) << ".manifest -outputresource:" << GetHostPathQ(product) << ";2"; - Execute(mt); - } - PutConsole(String().Cat() << product << " (" << GetFileInfo(product).length - << " B) created in " << GetPrintTime(linktime)); - break; - } - return true; - } - - IdeConsoleEndGroup(); - obj.Append(linkfile); - linkfile = obj; - return true; -} - -bool MscBuilder::Link(const Vector& linkfile, const String& linkoptions, bool createmap) -{ - int time = GetTickCount(); - if(!Wait()) - return false; - for(int i = 0; i < linkfile.GetCount(); i++) - if(GetFileTime(linkfile[i]) >= targettime) { - String link; - link << LinkerName() << " -nologo -machine:" << MachineName() - << " -pdb:" << GetHostPathQ(ForceExt(target, ".pdb")) - << " -out:" << GetHostPathQ(target); - if(HasFlag("FORCE_SIZE")){ - if(sContainsPchOptions(release_size_options)) - link << " -ltcg"; - } - else - if(HasFlag("FORCE_SPEED")) - if(sContainsPchOptions(release_options)) - link << " -ltcg"; - if(!HasFlag("MSC10") && !HasFlag("MSC10X64")) - if(HasAnyDebug()) - link << " -incremental:yes -debug -OPT:NOREF"; - else - link << " -incremental:no -release -OPT:REF,ICF"; - else - if(HasAnyDebug()) - link << " -debug -OPT:NOREF"; - else - link << " -release -OPT:REF,ICF"; - if(IsMscArm()) - link << " -subsystem:windowsce,4.20 /ARMPADCODE -NODEFAULTLIB:\"oldnames.lib\" "; - else - if(HasFlag("GUI") || IsMscArm()) - link << (HasFlag("WIN32") ? " -subsystem:windows" : " -subsystem:windowsce"); - else - link << " -subsystem:console"; - if(createmap) - link << " -MAP"; - if(HasFlag("DLL")) - link << " -DLL"; - for(i = 0; i < libpath.GetCount(); i++) - link << " -LIBPATH:\"" << libpath[i] << '\"'; - link << ' ' << linkoptions << ' '; - for(i = 0; i < linkfile.GetCount(); i++) - link << ' ' << GetHostPathQ(AppendExt(linkfile[i], ".lib")); - PutConsole("Linking..."); - bool error = false; - CustomStep(".pre-link", Null, error); - if(!error, Execute(link) == 0) { - CustomStep(".post-link", Null, error); - if((IsMsc86() || IsMsc64()) && HasFlag("SHARED")) { - String mt("mt -nologo -manifest "); - mt << GetHostPathQ(target) << ".manifest -outputresource:" << GetHostPathQ(target) - << (HasFlag("DLL") ? ";2" : ";1"); - Execute(mt); - } - PutConsole(String().Cat() << GetHostPath(target) << " (" << GetFileInfo(target).length - << " B) linked in " << GetPrintTime(time)); - return !error; - } - else { - DeleteFile(target); - return false; - } - } - PutConsole(String().Cat() << GetHostPath(target) << " (" << GetFileInfo(target).length - << " B) is up to date."); - return true; -} - -bool MscBuilder::Preprocess(const String& package, const String& file, const String& target, bool) -{ - FileOut out(target); - String packagepath = PackagePath(package); - Package pkg; - pkg.Load(packagepath); - return Execute(CmdLine(package, pkg) + " -E " + file, out); -} - -Builder *CreateMscBuilder() -{ - return new MscBuilder; -} - -INITBLOCK -{ - RegisterBuilder("MSC71", CreateMscBuilder); - RegisterBuilder("MSC8", CreateMscBuilder); - RegisterBuilder("MSC8X64", CreateMscBuilder); - RegisterBuilder("MSC8ARM", CreateMscBuilder); - RegisterBuilder("MSC9", CreateMscBuilder); - RegisterBuilder("MSC9X64", CreateMscBuilder); - RegisterBuilder("MSC10", CreateMscBuilder); - RegisterBuilder("MSC10X64", CreateMscBuilder); - RegisterBuilder("MSC9ARM", CreateMscBuilder); - RegisterBuilder("EVC_ARM", CreateMscBuilder); - RegisterBuilder("EVC_MIPS", CreateMscBuilder); - RegisterBuilder("EVC_SH3", CreateMscBuilder); - RegisterBuilder("EVC_SH4", CreateMscBuilder); - RegisterBuilder("INTEL", CreateMscBuilder); -} +#include "Builders.h" + +#include + +#ifdef PLATFORM_WIN32 +static bool HasTail(String s, const char *tail) +{ + int tl = (int)strlen(tail); + int sl = s.GetLength(); + if(sl < tl) + return false; + for(const char *p = s.GetIter(sl - tl); *p; p++, tail++) + if(*tail != '*' && *tail != *p) + return false; + return *tail == 0; +} +#endif + +static void AddObjectExports(const char *path, Index& out) +{ +#ifdef PLATFORM_WIN32 + FileMapping mapping; + if(!mapping.Open(path)) + return; + const byte *begin = mapping.Begin(); + const COFF_IMAGE_FILE_HEADER *hdr = (const COFF_IMAGE_FILE_HEADER *)begin; + if(hdr->Machine != COFF_IMAGE_FILE_MACHINE_I386) + return; + const COFF_IMAGE_SECTION_HEADER *sechdr = (const COFF_IMAGE_SECTION_HEADER *)(begin + + sizeof(COFF_IMAGE_FILE_HEADER) + hdr->SizeOfOptionalHeader); + Index code_sections; + for(int i = 0; i < hdr->NumberOfSections; i++) + if(sechdr[i].Characteristics & COFF_IMAGE_SCN_CNT_CODE) + code_sections.Add(i + 1); + const COFF_IMAGE_SYMBOL *symtbl = (const COFF_IMAGE_SYMBOL *)(begin + hdr->PointerToSymbolTable); + const char *strtbl = (const char *)(symtbl + hdr->NumberOfSymbols); + for(int i = 0; i < (int)hdr->NumberOfSymbols; i++) + { + const COFF_IMAGE_SYMBOL& sym = symtbl[i]; + if(sym.StorageClass == COFF_IMAGE_SYM_CLASS_EXTERNAL && code_sections.Find(sym.SectionNumber) >= 0) + { + String name = COFFSymbolName(sym, strtbl); + if(!HasTail(name, "AEPAXI@Z")) + { + if(*name == '_' && name.Find('@') < 0) + name.Remove(0, 1); + out.FindAdd(name); + } + } + i += sym.NumberOfAuxSymbols; + } +#endif +} + +void MscBuilder::AddFlags(Index& cfg) +{ + cfg.FindAdd("MSC"); +} + +String MscBuilder::CmdLine(const String& package, const Package& pkg) +{ + String cc; + if(HasFlag("ARM")) + cc = "clarm"; + else + if(HasFlag("MIPS")) + cc = "clmips"; + else + if(HasFlag("SH3")) + cc = "shcl /Qsh3"; + else + if(HasFlag("SH4")) + cc = "shcl /Qsh4"; + else + if(HasFlag("MSC8ARM")) + cc = "cl -GS- "; + else + cc = HasFlag("INTEL") ? "icl" : "cl"; +// TRC 080605-documentation says Wp64 works in 32-bit compilation only +// cc << (IsMsc64() ? " -nologo -Wp64 -W3 -GR -c" : " -nologo -W3 -GR -c"); + cc << " -nologo -W3 -GR -c"; + cc << IncludesDefinesTargetTime(package, pkg); + + return cc; +} + +String MscBuilder::MachineName() const +{ + if(HasFlag("ARM")) return "ARM"; + if(HasFlag("MIPS")) return "MIPS"; + if(HasFlag("SH3")) return "SH3"; + if(HasFlag("SH4")) return "SH4"; + if(IsMscArm()) return "ARM"; + if(IsMsc64()) return "x64"; + if(HasFlag("WIN32")) return "I386"; + return "IX86"; +} + +bool MscBuilder::IsMsc89() const +{ + return IsMsc86() || IsMsc64() || IsMscArm(); +} + +bool MscBuilder::IsMsc86() const +{ + return HasFlag("MSC8") || HasFlag("MSC9") || HasFlag("MSC10"); +} + +bool MscBuilder::IsMscArm() const +{ + return HasFlag("MSC8ARM") || HasFlag("MSC9ARM"); +} + +bool MscBuilder::IsMsc64() const +{ + return HasFlag("MSC8X64") || HasFlag("MSC9X64") || HasFlag("MSC10X64"); +} + +String MscBuilder::LinkerName() const +{ + if(HasFlag("ULD")) return "uld"; + if(HasFlag("INTEL")) return "xilink"; + return "link"; +} + +static bool sContainsPchOptions(const String& x) +{ + Index a = Split(x, ' '); + return a.Find("-GL") >= 0 || a.Find("/GL") >= 0 || a.Find("-Y-") >= 0 || a.Find("/Y-") >= 0 + || a.Find("-Yc") >= 0 || a.Find("/Yc") >= 0 || a.Find("-Yd") >= 0 || a.Find("/Yd") >= 0 + || a.Find("-Yl") >= 0 || a.Find("/Yl") >= 0 || a.Find("-Yu") >= 0 || a.Find("/Yu") >= 0 + || a.Find("-YX") >= 0 || a.Find("/YX") >= 0; +} + +bool MscBuilder::HasAnyDebug() const +{ + return HasFlag("DEBUG") || HasFlag("DEBUG_MINIMAL") || HasFlag("DEBUG_FULL"); +} + +String MscBuilder::PdbPch(String package, int slot, bool do_pch) const +{ + String pkg_slot = NFormat("%s-%d", GetAnyFileName(package), slot + 1); + String pdb = GetHostPathQ(CatAnyPath(outdir, pkg_slot + ".pdb")); + String cc; + cc << " -Gy -Fd" << pdb; + if(do_pch && !IsMsc89()) // MSC8/9 does not support automatic precompiled headers... + cc << " -YX -Fp" << GetHostPathQ(CatAnyPath(outdir, pkg_slot + ".pch")) << ' '; + return cc; +} + +bool MscBuilder::BuildPackage(const String& package, Vector& linkfile, String& linkoptions, + const Vector& all_uses, const Vector& all_libraries, int opt) +{ + int i; + String packagepath = PackagePath(package); + Package pkg; + pkg.Load(packagepath); + String packagedir = GetFileFolder(packagepath); + ChDir(packagedir); + PutVerbose("cd " + packagedir); + IdeConsoleBeginGroup(package); + Vector obj; + + bool is_shared = HasFlag("SO"), + is_clr = HasFlag("CLR"); + + String cc = CmdLine(package, pkg); + if(HasFlag("EVC")) { + if(!HasFlag("SH3") && !HasFlag("SH4")) + cc << " -Gs8192"; // disable stack checking + cc << " -GF" // read-only string pooling + " -GX-"; // turn off exception handling + } + else + if(is_clr) + cc << " -EHac"; + else + if(IsMsc89()) + cc << " -EHsc"; + else + cc << " -GX"; +// String pdb = GetHostPathQ(CatAnyPath(outdir, GetAnyFileName(package) + ".pdb")); +// String pch; +// if(!HasFlag("MSC8")) // MSC8 does not support automatic precompiled headers... +// pch << " -YX -Fp" << GetHostPathQ(CatAnyPath(outdir, GetAnyFileName(package) + ".pch")) << ' '; +// cc << " -Gy -Fd" << pdb; + if(HasFlag("SSE2") && !IsMsc64()) + cc << " /arch:SSE2"; + if(HasFlag("DEBUG_MINIMAL")) + cc << " -Zd"; + if(HasFlag("DEBUG_FULL")) + cc << " -Zi"; + cc << ' ' << Gather(pkg.option, config.GetKeys()); + cc << (HasFlag("SHARED") || is_shared || is_clr ? " -MD" + : (HasFlag("MT") || IsMsc89()) ? " -MT" : " -ML"); + + String cc_size = cc; + String cc_speed = cc; + bool release = false; + + if(HasFlag("DEBUG")) + cc << "d " << debug_options; + else { + release = true; + cc << ' ' << release_size_options; + cc_speed << ' ' << release_options; + if(opt == R_SPEED || pkg.optimize_speed) + cc = cc_speed; + } + + + Vector sfile, isfile; + Vector soptions, isoptions; + Vector optimize, ioptimize; + Vector sobjfile; + bool error = false; + + for(i = 0; i < pkg.GetCount(); i++) { + if(!IdeIsBuilding()) + return false; + if(!pkg[i].separator) { + String gop = Gather(pkg[i].option, config.GetKeys()); + Vector srcfile = CustomStep(pkg[i], package, error); + if(srcfile.GetCount() == 0) + error = true; + for(int j = 0; j < srcfile.GetCount(); j++) { + String fn = srcfile[j]; + String ext = ToLower(GetFileExt(fn)); + if(ext == ".c" || ext == ".cpp" || ext == ".cc" || ext == ".cxx" || ext == ".rc" || ext == ".brc") { + sfile.Add(fn); + soptions.Add(gop); + optimize.Add(release && pkg[i].optimize_speed && opt == R_OPTIMAL); + } + else + if(ext == ".icpp") { + isfile.Add(fn); + isoptions.Add(gop); + ioptimize.Add(release && pkg[i].optimize_speed && opt == R_OPTIMAL); + } + else + if(ext == ".obj") + obj.Add(fn); + else + if(ext == ".lib") + linkfile.Add(fn); + } + } + } + + if(HasFlag("BLITZ")) { + Blitz b = BlitzStep(sfile, soptions, obj, ".obj", optimize); + if(b.build) { + PutConsole("BLITZ:" + b.info); + int slot = AllocSlot(); + if(slot < 0 || ! Run(cc + PdbPch(package, slot, false) + + " -Tp " + GetHostPathQ(b.path) + " -Fo" + GetHostPathQ(b.object), slot, GetHostPath(b.object), b.count)) + error = true; + } + } + + int first_ifile = sfile.GetCount(); + sfile.AppendPick(isfile); + soptions.AppendPick(isoptions); + optimize.AppendPick(ioptimize); + + int ccount = 0; + +// if(sContainsPchOptions(cc)) +// pch = Null; + + for(i = 0; i < sfile.GetCount(); i++) { + if(!IdeIsBuilding()) + return false; + String fn = sfile[i]; + String ext = ToLower(GetFileExt(fn)); + bool rc = (ext == ".rc"); + bool brc = (ext == ".brc"); + bool init = (i >= first_ifile); + String objfile = CatAnyPath(outdir, GetFileTitle(fn) + (rc ? "$rc.obj" : brc ? "$brc.obj" : ".obj")); + if(HdependFileTime(fn) > GetFileTime(objfile)) { + int time = GetTickCount(); + bool execerr = false; + if(rc) { + PutConsole(GetFileNamePos(fn)); + int slot = AllocSlot(); + if(slot < 0 || !Run("rc /fo" + GetHostPathQ(objfile) + Includes(" /i", package, pkg) + + ' ' + GetHostPathQ(fn), slot, GetHostPath(objfile), 1)) + execerr = true; + } + else + if(brc) { + try { +// String hfn = GetHostPath(fn); + String brcdata = LoadFile(fn); + if(brcdata.IsVoid()) + throw Exc(NFormat("error reading file '%s'", fn)); + CParser parser(brcdata, fn); + String fo = BrcToC(GetHostPath(objfile), parser, GetFileDirectory(fn), package, pkg); + String tmpfile = ForceExt(objfile, ".c"); + SaveFile(tmpfile, fo); + int slot = AllocSlot(); + if(slot < 0 || !Run(cc + " -Tc " + GetHostPathQ(tmpfile) + " -Fo" + GetHostPath(objfile), + slot, GetHostPath(objfile), 1)) + throw Exc(NFormat("Error compiling binary object '%s'.", objfile)); + } + catch(Exc e) { + PutConsole(e); + execerr = true; + } + } + else { + String c = cc; + if(optimize[i]) + c = cc_speed; + int slot = AllocSlot(); + if(slot < 0 || !Run(c + PdbPch(package, slot, !sContainsPchOptions(cc) && !sContainsPchOptions(soptions[i])) + + " " + soptions[i] + (ext == ".c" ? " -Tc " : " -Tp ") + + GetHostPathQ(fn) + " -Fo" + GetHostPathQ(objfile), slot, GetHostPath(objfile), 1)) + execerr = true; + } + if(execerr) + DeleteFile(objfile); + error |= execerr; + PutVerbose("compiled in " + GetPrintTime(time)); + ccount++; + } + if(init) + linkfile.Add(objfile); + else + obj.Add(objfile); + } + if(error) { +// ShowTime(ccount, time); + IdeConsoleEndGroup(); + return false; + } + + Vector pkglibs = Split(Gather(pkg.library, config.GetKeys()), ' '); + for(int i = 0; i < pkglibs.GetCount(); i++) { + String libfile = AppendExt(pkglibs[i], ".lib"); + if(!IsFullPath(libfile)) { + for(int p = 0; p < libpath.GetCount(); p++) { + String nf = NormalizePath(libfile, libpath[p]); + if(FileExists(nf)) { + libfile = nf; + break; + } + } + } + linkfile.Add(libfile); + } + linkoptions << ' ' << Gather(pkg.link, config.GetKeys()); + + int linktime = GetTickCount(); + if(!HasFlag("MAIN")) { + if(HasFlag("BLITZ") || HasFlag("NOLIB")) { + linkfile.Append(obj); +// ShowTime(ccount, time); + IdeConsoleEndGroup(); + return true; + } + String product; + if(is_shared) + product = GetSharedLibPath(package); + else + product = CatAnyPath(outdir, GetAnyFileName(package) + ".lib"); + Time producttime = GetFileTime(product); + linkfile.Add(ForceExt(product, ".lib")); + if(!Wait()) { + IdeConsoleEndGroup(); + return false; + } + Vector objinfo = host->GetFileInfo(obj); + for(int i = 0; i < obj.GetCount(); i++) + if(objinfo[i] > producttime) { + String linker, lib; + if(is_shared) { + linker << LinkerName() << "-dll -nologo "; + lib << "-machine:" << MachineName() + << " -pdb:" << GetHostPathQ(ForceExt(product, ".pdb")) + << " -out:" << GetHostPathQ(product); + if(!HasFlag("MSC10") && !HasFlag("MSC10X64")) + lib << " -incremental:no"; + if(HasFlag("FORCE_SIZE")){ + if(sContainsPchOptions(release_size_options)) + lib << " -ltcg"; + } + else + if(HasFlag("FORCE_SPEED")) + if(sContainsPchOptions(release_options)) + lib << " -ltcg"; + if(HasAnyDebug()) + lib << " -debug -OPT:NOREF"; + else + lib << " -release -OPT:REF,ICF"; + if(IsMscArm()) + lib << " -subsystem:windowsce,4.20 /ARMPADCODE"; + else + if(HasFlag("GUI")) + lib << (HasFlag("WIN32") ? " -subsystem:windows" + : " -subsystem:windowsce"); + else + lib << " -subsystem:console"; + Index exports; + for(int o = 0; o < obj.GetCount(); o++) + AddObjectExports(obj[o], exports); + String def; + def << "LIBRARY " << AsCString(GetFileName(product)) << "\n\n" + "EXPORTS\n"; + for(int o = 0; o < exports.GetCount(); o++) + def << '\t' << exports[o] << "\n"; //" @" << (o + 1) << "\n"; + String deffile = ForceExt(product, ".def"); + if(!SaveChangedFile(deffile, def)) + { + PutConsole(NFormat("%s: error saving file", deffile)); + return false; + } + lib << " -def:" << GetHostPathQ(deffile); + for(int i = 0; i < libpath.GetCount(); i++) + lib << " -LIBPATH:" << GetHostPathQ(libpath[i]); + lib << ' ' << Gather(pkg.link, config.GetKeys()); + for(int i = 0; i < all_uses.GetCount(); i++) + lib << ' ' << GetHostPathQ(ForceExt(GetSharedLibPath(all_uses[i]), ".lib")); + for(int i = 0; i < all_libraries.GetCount(); i++) { + String libfile = AppendExt(all_libraries[i], ".lib"); + if(!IsFullPath(libfile)) { + for(int p = 0; p < libpath.GetCount(); p++) { + String nf = NormalizePath(libfile, libpath[p]); + if(FileExists(nf)) { + libfile = nf; + break; + } + } + } + lib << ' ' << GetHostPathQ(libfile); + } + } + else{ + linker << (HasFlag("INTEL") ? "xilib" : "link /lib") << " -nologo "; + if(HasFlag("FORCE_SIZE")){ + if(sContainsPchOptions(release_size_options)) + lib << " -ltcg"; + } + else + if(HasFlag("FORCE_SPEED")) + if(sContainsPchOptions(release_options)) + lib << " -ltcg"; + lib << " -out:" << GetHostPathQ(product) << ' ' << Gather(pkg.link, config.GetKeys()); + } + for(int i = 0; i < obj.GetCount(); i++) + lib << ' ' << GetHostPathQ(obj[i]); + PutConsole("Creating library..."); + IdeConsoleEndGroup(); + DeleteFile(product); + String tmpFileName; + if(linker.GetCount() + lib.GetCount() >= 8192) + { + tmpFileName = GetTempFileName(); + // we can't simply put all data on a single line + // as it has a limit of around 130000 chars too, so we split + // in multiple lines + FileOut f(tmpFileName); + while(lib != "") + { + int found = 0; + bool quotes = false; + int lim = min(8192, lib.GetCount()); + for(int i = 0; i < lim; i++) + { + char c = lib[i]; + if(isspace(c) && !quotes) + found = i; + else if(c == '"') + quotes = !quotes; + } + if(!found) + found = lib.GetCount(); + f.PutLine(lib.Left(found)); + lib.Remove(0, found); + } + f.Close(); + linker << "@" << tmpFileName; + } + else + linker << lib; + bool res = Execute(linker); + if(tmpFileName != "") + FileDelete(tmpFileName); + if(res) { + DeleteFile(product); + return false; + } + else + if((IsMsc86() || IsMsc64()) && is_shared) { + String mt("mt -nologo -manifest "); + mt << GetHostPathQ(product) << ".manifest -outputresource:" << GetHostPathQ(product) << ";2"; + Execute(mt); + } + PutConsole(String().Cat() << product << " (" << GetFileInfo(product).length + << " B) created in " << GetPrintTime(linktime)); + break; + } + return true; + } + + IdeConsoleEndGroup(); + obj.Append(linkfile); + linkfile = obj; + return true; +} + +bool MscBuilder::Link(const Vector& linkfile, const String& linkoptions, bool createmap) +{ + int time = GetTickCount(); + if(!Wait()) + return false; + for(int i = 0; i < linkfile.GetCount(); i++) + if(GetFileTime(linkfile[i]) >= targettime) { + String link; + link << LinkerName() << " -nologo -machine:" << MachineName() + << " -pdb:" << GetHostPathQ(ForceExt(target, ".pdb")) + << " -out:" << GetHostPathQ(target); + if(HasFlag("FORCE_SIZE")){ + if(sContainsPchOptions(release_size_options)) + link << " -ltcg"; + } + else + if(HasFlag("FORCE_SPEED")) + if(sContainsPchOptions(release_options)) + link << " -ltcg"; + if(!HasFlag("MSC10") && !HasFlag("MSC10X64")) + if(HasAnyDebug()) + link << " -incremental:yes -debug -OPT:NOREF"; + else + link << " -incremental:no -release -OPT:REF,ICF"; + else + if(HasAnyDebug()) + link << " -debug -OPT:NOREF"; + else + link << " -release -OPT:REF,ICF"; + if(IsMscArm()) + link << " -subsystem:windowsce,4.20 /ARMPADCODE -NODEFAULTLIB:\"oldnames.lib\" "; + else + if(HasFlag("GUI") || IsMscArm()) + link << (HasFlag("WIN32") ? " -subsystem:windows" : " -subsystem:windowsce"); + else + link << " -subsystem:console"; + if(createmap) + link << " -MAP"; + if(HasFlag("DLL")) + link << " -DLL"; + for(i = 0; i < libpath.GetCount(); i++) + link << " -LIBPATH:\"" << libpath[i] << '\"'; + link << ' ' << linkoptions << ' '; + for(i = 0; i < linkfile.GetCount(); i++) + link << ' ' << GetHostPathQ(AppendExt(linkfile[i], ".lib")); + PutConsole("Linking..."); + bool error = false; + CustomStep(".pre-link", Null, error); + if(!error && Execute(link) == 0) { + CustomStep(".post-link", Null, error); + if((IsMsc86() || IsMsc64()) && HasFlag("SHARED")) { + String mt("mt -nologo -manifest "); + mt << GetHostPathQ(target) << ".manifest -outputresource:" << GetHostPathQ(target) + << (HasFlag("DLL") ? ";2" : ";1"); + Execute(mt); + } + PutConsole(String().Cat() << GetHostPath(target) << " (" << GetFileInfo(target).length + << " B) linked in " << GetPrintTime(time)); + return !error; + } + else { + DeleteFile(target); + return false; + } + } + PutConsole(String().Cat() << GetHostPath(target) << " (" << GetFileInfo(target).length + << " B) is up to date."); + return true; +} + +bool MscBuilder::Preprocess(const String& package, const String& file, const String& target, bool) +{ + FileOut out(target); + String packagepath = PackagePath(package); + Package pkg; + pkg.Load(packagepath); + return Execute(CmdLine(package, pkg) + " -E " + file, out); +} + +Builder *CreateMscBuilder() +{ + return new MscBuilder; +} + +INITBLOCK +{ + RegisterBuilder("MSC71", CreateMscBuilder); + RegisterBuilder("MSC8", CreateMscBuilder); + RegisterBuilder("MSC8X64", CreateMscBuilder); + RegisterBuilder("MSC8ARM", CreateMscBuilder); + RegisterBuilder("MSC9", CreateMscBuilder); + RegisterBuilder("MSC9X64", CreateMscBuilder); + RegisterBuilder("MSC10", CreateMscBuilder); + RegisterBuilder("MSC10X64", CreateMscBuilder); + RegisterBuilder("MSC9ARM", CreateMscBuilder); + RegisterBuilder("EVC_ARM", CreateMscBuilder); + RegisterBuilder("EVC_MIPS", CreateMscBuilder); + RegisterBuilder("EVC_SH3", CreateMscBuilder); + RegisterBuilder("EVC_SH4", CreateMscBuilder); + RegisterBuilder("INTEL", CreateMscBuilder); +} diff --git a/uppsrc/ide/Core/Host.cpp b/uppsrc/ide/Core/Host.cpp index 2fd3dff42..a91b25f20 100644 --- a/uppsrc/ide/Core/Host.cpp +++ b/uppsrc/ide/Core/Host.cpp @@ -1,572 +1,572 @@ -#include "Core.h" - -#define LLOG(x) - -#include - -String LocalHost::GetEnvironment() -{ - return environment; -} - -String LocalHost::GetHostPath(const String& path) -{ - return path; -} - -String LocalHost::GetLocalPath(const String& path) -{ - return path; -} - -String LocalHost::NormalizePath(const String& path) -{ - return ::NormalizePath(path); -} - -Vector LocalHost::GetFileInfo(const Vector& path) -{ - Vector fi; - for(int i = 0; i < path.GetCount(); i++) { - FindFile ff(path[i]); - FileInfo& f = fi.Add(); - if(ff) { - (Time&)f = ff.GetLastWriteTime(); -#ifdef PLATFORM_WIN32 - f.second = f.second & ~1; // FAT vs NTFS accuracy fix -#endif - f.length = ff.IsFile() ? (int)ff.GetLength() : -1; - } - else { - (Time&)f = Time::Low(); - f.length = Null; - } - } - return fi; -} - -void LocalHost::DeleteFile(const Vector& path) -{ - for(int i = 0; i < path.GetCount(); i++) - ::DeleteFile(path[i]); -} - -void LocalHost::DeleteFolderDeep(const String& folder) -{ - ::DeleteFolderDeep(folder); -} - -void LocalHost::ChDir(const String& path) -{ -#ifdef PLATFORM_WIN32 - SetCurrentDirectory(path); -#endif -#ifdef PLATFORM_POSIX - chdir(path); -#endif - if(cmdout) - *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; -} - -void LocalHost::DoDir(const String& dir) -{ - if(dir.GetLength() > 3) { - DoDir(GetFileFolder(dir)); - *cmdout << "mkdir \"" << dir << "\"\n"; - } -} - -void LocalHost::RealizeDir(const String& path) -{ - RealizeDirectory(path); - if(cmdout) - DoDir(path); -} - -void LocalHost::SaveFile(const String& path, const String& data) -{ - ::SaveFile(path, data); -} - -String LocalHost::LoadFile(const String& path) -{ - return ::LoadFile(path); -} - -int LocalHost::Execute(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::ExecuteWithInput(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::Execute(const char *cmdline, Stream& out) -{ - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); -} - -bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); -} - -bool LocalHost::Wait() -{ - return IdeConsoleWait(); -} - -One LocalHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return ::StartProcess(FindCommand(exedirs, cmdline), environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -#ifdef PLATFORM_POSIX -//#BLITZ_APPROVE -#include -#include -#include - -static Vector& sPid() -{ - static Vector q; - return q; -} - -void sCleanZombies(int signal_number) -{ - Vector& pid = sPid(); - int i = 0; - while(i < pid.GetCount()) - if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) - pid.Remove(i); - else - i++; -} -#endif - -String LinuxHostConsole = "/usr/bin/xterm -e"; - -void LocalHost::Launch(const char *_cmdline, bool console) -{ - String cmdline = FindCommand(exedirs, _cmdline); - PutVerbose(cmdline); -#ifdef PLATFORM_WIN32 - if(console) - cmdline = GetExeFilePath() + " ! " + cmdline; - int n = cmdline.GetLength() + 1; - Buffer cmd(n); - memcpy(cmd, cmdline, n); - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - PROCESS_INFORMATION pi; - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - String ev = ToSystemCharset(environment); - Buffer env(ev.GetCount() + 1); - memcpy(env, ev, ev.GetCount() + 1); - if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, - NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, - ~env, NULL, &si, &pi)) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - else - PutConsole("Unable to launch " + String(_cmdline)); -#endif -#ifdef PLATFORM_POSIX - String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); - int c = LinuxHostConsole.FindFirstOf(" "); - String lc = c < 0 ? LinuxHostConsole : LinuxHostConsole.Left(c); - if(FileExists(lc)){ - if(console){ - FileStream out(script, FileStream::CREATE, 0777); - out << "#!/bin/sh\n" - << cmdline << '\n' - << "echo \"<--- Finished, press any key to close the window --->\"\nread\n"; - cmdline = LinuxHostConsole + " sh " + script; - } - } - else - if(LinuxHostConsole.GetCount()) - PutConsole("Warning: Terminal '"+lc+"' not found, executing in background."); - Buffer cmd_buf(strlen(cmdline) + 1); - char *cmd_out = cmd_buf; - Vector args; - const char *p = cmdline; - const char *b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - while(*p && *p++ != '\"') - ; - args.Add(cmd_out); - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - - while(*p) - if((byte)*p <= ' ') - p++; - else { - args.Add(cmd_out); - b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - { - memcpy(cmd_out, b, p - b - 1); - cmd_out += p - b - 1; - b = p; - while(*p && *p != '\"') - p++; - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - if(*p == '\"') - p++; - b = p; - } - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - } - - args.Add(NULL); - - ONCELOCK { - struct sigaction sigchld_action; - memset(&sigchld_action, 0, sizeof(sigchld_action)); - sigchld_action.sa_handler = sCleanZombies; - sigaction(SIGCHLD, &sigchld_action, NULL); - } - - pid_t pid = fork(); - if(pid == 0) - { - const char *from = environment; - Vector env; - while(*from) { - env.Add(from); - from += strlen(from) + 1; - } - env.Add(NULL); - const char **envp = env.Begin(); - execve(args[0], args, (char *const *)envp); - abort(); - } - LLOG("Launch pid: " << pid); - sPid().Add(pid); -#endif -} - -void LocalHost::AddFlags(Index& cfg) -{ -#if defined(PLATFORM_WIN32) - cfg.Add("WIN32"); -#endif - -#ifdef PLATFORM_LINUX - cfg.Add("LINUX"); -#endif - -#ifdef PLATFORM_POSIX - cfg.Add("POSIX"); -#endif - -#ifdef PLATFORM_BSD - cfg.Add("BSD"); -#endif - -#ifdef PLATFORM_FREEBSD - cfg.Add("FREEBSD"); -#endif - -#ifdef PLATFORM_OPENBSD - cfg.Add("OPENBSD"); -#endif - -#ifdef PLATFORM_NETBSD - cfg.Add("NETBSD"); -#endif - -#ifdef PLATFORM_SOLARIS - cfg.Add("SOLARIS"); -#endif - -#ifdef PLATFORM_OSX11 - cfg.Add("OSX11"); -#endif -} - -static bool IsSamePath(const char *a, const char *b, int count) { - for(; --count >= 0; a++, b++) - if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) - return false; - return true; -} - -String RemoteHost::GetEnvironment() -{ - return environment; -} - -String RemoteHost::GetHostPath(const String& path) -{ - bool slash = (os_type != "WINDOWS"); - for(int i = 0; i < path_map_local.GetCount(); i++) { - String lc = path_map_local[i]; - if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) - { - String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); - return slash ? UnixPath(r) : WinPath(r); - } - } - return slash ? UnixPath(path) : WinPath(path); -} - -String RemoteHost::GetLocalPath(const String& path) -{ - for(int i = 0; i < path_map_remote.GetCount(); i++) { - String rc = path_map_remote[i]; - if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) - return path_map_local[i] + path.Mid(rc.GetLength()); - } - if(!memcmp(path, "/cygdrive/", 10)) - { - const char *s = path.Begin() + 10; - String out; - if(*s) - out << *s++ << ':'; - out << s; - return out; - } - return NativePath(path); -} - -String RemoteHost::NormalizePath(const String& path) -{ - return path; -} - -String RemoteHost::RemoteExec(String cmd) -{ - Socket socket; - String sockerr; -/* - String hostname = host; - int port = 2346; - int ppos = hostname.Find(':'); - if(ppos >= 0) - { - port = atoi(host.GetIter(ppos + 1)); - hostname.Trim(ppos); - } -*/ - if(!ClientSocket(socket, host, port, true, NULL, 2000)) { - PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); - return String::GetVoid(); - } - socket.Write(cmd); - socket.Write("\0", 1); - return socket.ReadUntil('\0', Null, 10000000); -} - -Vector RemoteHost::GetFileInfo(const Vector& path) -{ - VectorMap out; - out.Reserve(path.GetCount()); - String request; - request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; - for(int i = 0; i < path.GetCount(); i++) - { - String hp = GetHostPath(path[i]); - request << hp << "\n"; - FileInfo& fi = out.Add(hp); - (Time&)fi = Time::Low(); - fi.length = Null; - } - String result = RemoteExec(request); - const char *p = result; - while(*p) - { - const char *b = p; - while(*p && *p != '\n' && *p != '\t') - p++; - String fn(b, p); - Time time = Time::Low(); - int size = Null; - if(*p == '\t') - { - int t = ScanInt(p + 1, &p); - if(!IsNull(t)) - time = TimeBase() + t; - if(*p == '\t') - size = ScanInt(p + 1, &p); - } - int ifn = out.Find(fn); - if(ifn >= 0) - { - (Time&)out[ifn] = time; - out[ifn].length = size; - } - while(*p && *p++ != '\n') - ; - } - return out.PickValues(); -} - -void RemoteHost::DeleteFile(const Vector& path) -{ - String request = "-"; - for(int i = 0; i < path.GetCount(); i++) - request << GetHostPath(path[i]) << "\n"; - String out = RemoteExec(request); - if(!IsNull(out) && out != "OK") - PutVerbose(out); -} - -void RemoteHost::DeleteFolderDeep(const String& folder) -{ - String out = RemoteExec("~" + GetHostPath(folder)); - if(out != "OK") - PutConsole(out); -} - -void RemoteHost::ChDir(const String& path) -{ - chdir_path = GetHostPath(path); -} - -void RemoteHost::RealizeDir(const String& path) -{ - RemoteExec("*" + GetHostPath(path)); -} - -void RemoteHost::SaveFile(const String& path, const String& data) -{ - String request; - request << ">" << GetHostPath(path) - << "\t" << int(GetSysTime() - TimeBase()) - << "\t" << data.GetLength() - << "\t" << ASCII85Encode(BZ2Compress(data)) - << "\n"; - String out = RemoteExec(request); - if(out != "OK") - PutConsole(out); -} - -String RemoteHost::LoadFile(const String& path) -{ - String hpath = GetHostPath(path); - String request = "^" + hpath; - String out = RemoteExec(request); - const char *p = out; - while(*p && *p != '\n' && *p != '\t') - p++; - if(*p++ != '\t') - return String::GetVoid(); - int len = ScanInt(p, &p); - if(IsNull(len) || len <= 0 || *p++ != '\t') - return String::GetVoid(); - String data = BZ2Decompress(ASCII85Decode(p)); - if(data.GetLength() != len) - { - PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", - hpath, data.GetLength(), len)); - return String::GetVoid(); - } - return data; -} - -int RemoteHost::Execute(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::ExecuteWithInput(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::Execute(const char *cmdline, Stream& out) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); -} - -bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); -} - -bool RemoteHost::Wait() -{ - return IdeConsoleWait(); -} - -One RemoteHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -void RemoteHost::Launch(const char *_cmdline, bool) -{ -} - -void RemoteHost::AddFlags(Index& cfg) -{ - cfg.Add(os_type); -} +#include "Core.h" + +#define LLOG(x) + +#include + +String LocalHost::GetEnvironment() +{ + return environment; +} + +String LocalHost::GetHostPath(const String& path) +{ + return path; +} + +String LocalHost::GetLocalPath(const String& path) +{ + return path; +} + +String LocalHost::NormalizePath(const String& path) +{ + return ::NormalizePath(path); +} + +Vector LocalHost::GetFileInfo(const Vector& path) +{ + Vector fi; + for(int i = 0; i < path.GetCount(); i++) { + FindFile ff(path[i]); + FileInfo& f = fi.Add(); + if(ff) { + (Time&)f = ff.GetLastWriteTime(); +#ifdef PLATFORM_WIN32 + f.second = f.second & ~1; // FAT vs NTFS accuracy fix +#endif + f.length = ff.IsFile() ? (int)ff.GetLength() : -1; + } + else { + (Time&)f = Time::Low(); + f.length = Null; + } + } + return fi; +} + +void LocalHost::DeleteFile(const Vector& path) +{ + for(int i = 0; i < path.GetCount(); i++) + ::DeleteFile(path[i]); +} + +void LocalHost::DeleteFolderDeep(const String& folder) +{ + ::DeleteFolderDeep(folder); +} + +void LocalHost::ChDir(const String& path) +{ +#ifdef PLATFORM_WIN32 + SetCurrentDirectory(path); +#endif +#ifdef PLATFORM_POSIX + chdir(path); +#endif + if(cmdout) + *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; +} + +void LocalHost::DoDir(const String& dir) +{ + if(dir.GetLength() > 3) { + DoDir(GetFileFolder(dir)); + *cmdout << "mkdir \"" << dir << "\"\n"; + } +} + +void LocalHost::RealizeDir(const String& path) +{ + RealizeDirectory(path); + if(cmdout) + DoDir(path); +} + +void LocalHost::SaveFile(const String& path, const String& data) +{ + ::SaveFile(path, data); +} + +String LocalHost::LoadFile(const String& path) +{ + return ::LoadFile(path); +} + +int LocalHost::Execute(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::ExecuteWithInput(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::Execute(const char *cmdline, Stream& out) +{ + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); +} + +bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); +} + +bool LocalHost::Wait() +{ + return IdeConsoleWait(); +} + +One LocalHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + return ::StartProcess(FindCommand(exedirs, cmdline), environment, REMOTE_TIMEOUT); + } + catch(...) { + return NULL; + } +} + +#ifdef PLATFORM_POSIX +//#BLITZ_APPROVE +#include +#include +#include + +static Vector& sPid() +{ + static Vector q; + return q; +} + +void sCleanZombies(int signal_number) +{ + Vector& pid = sPid(); + int i = 0; + while(i < pid.GetCount()) + if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) + pid.Remove(i); + else + i++; +} +#endif + +String LinuxHostConsole = "/usr/bin/xterm -e"; + +void LocalHost::Launch(const char *_cmdline, bool console) +{ + String cmdline = FindCommand(exedirs, _cmdline); + PutVerbose(cmdline); +#ifdef PLATFORM_WIN32 + if(console) + cmdline = GetExeFilePath() + " ! " + cmdline; + int n = cmdline.GetLength() + 1; + Buffer cmd(n); + memcpy(cmd, cmdline, n); + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + PROCESS_INFORMATION pi; + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + String ev = ToSystemCharset(environment); + Buffer env(ev.GetCount() + 1); + memcpy(env, ev, ev.GetCount() + 1); + if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, + NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, + ~env, NULL, &si, &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + PutConsole("Unable to launch " + String(_cmdline)); +#endif +#ifdef PLATFORM_POSIX + String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); + int c = LinuxHostConsole.FindFirstOf(" "); + String lc = c < 0 ? LinuxHostConsole : LinuxHostConsole.Left(c); + if(FileExists(lc)){ + if(console){ + FileStream out(script, FileStream::CREATE, 0777); + out << "#!/bin/sh\n" + << cmdline << '\n' + << "echo \"<--- Finished, press any key to close the window --->\"\nread\n"; + cmdline = LinuxHostConsole + " sh " + script; + } + } + else + if(LinuxHostConsole.GetCount()) + PutConsole("Warning: Terminal '"+lc+"' not found, executing in background."); + Buffer cmd_buf(strlen(cmdline) + 1); + char *cmd_out = cmd_buf; + Vector args; + const char *p = cmdline; + const char *b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + while(*p && *p++ != '\"') + ; + args.Add(cmd_out); + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + + while(*p) + if((byte)*p <= ' ') + p++; + else { + args.Add(cmd_out); + b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + { + memcpy(cmd_out, b, p - b - 1); + cmd_out += p - b - 1; + b = p; + while(*p && *p != '\"') + p++; + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + if(*p == '\"') + p++; + b = p; + } + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + } + + args.Add(NULL); + + ONCELOCK { + struct sigaction sigchld_action; + memset(&sigchld_action, 0, sizeof(sigchld_action)); + sigchld_action.sa_handler = sCleanZombies; + sigaction(SIGCHLD, &sigchld_action, NULL); + } + + pid_t pid = fork(); + if(pid == 0) + { + const char *from = environment; + Vector env; + while(*from) { + env.Add(from); + from += strlen(from) + 1; + } + env.Add(NULL); + const char **envp = env.Begin(); + execve(args[0], args, (char *const *)envp); + abort(); + } + LLOG("Launch pid: " << pid); + sPid().Add(pid); +#endif +} + +void LocalHost::AddFlags(Index& cfg) +{ +#if defined(PLATFORM_WIN32) + cfg.Add("WIN32"); +#endif + +#ifdef PLATFORM_LINUX + cfg.Add("LINUX"); +#endif + +#ifdef PLATFORM_POSIX + cfg.Add("POSIX"); +#endif + +#ifdef PLATFORM_BSD + cfg.Add("BSD"); +#endif + +#ifdef PLATFORM_FREEBSD + cfg.Add("FREEBSD"); +#endif + +#ifdef PLATFORM_OPENBSD + cfg.Add("OPENBSD"); +#endif + +#ifdef PLATFORM_NETBSD + cfg.Add("NETBSD"); +#endif + +#ifdef PLATFORM_SOLARIS + cfg.Add("SOLARIS"); +#endif + +#ifdef PLATFORM_OSX11 + cfg.Add("OSX11"); +#endif +} + +static bool IsSamePath(const char *a, const char *b, int count) { + for(; --count >= 0; a++, b++) + if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) + return false; + return true; +} + +String RemoteHost::GetEnvironment() +{ + return environment; +} + +String RemoteHost::GetHostPath(const String& path) +{ + bool slash = (os_type != "WINDOWS"); + for(int i = 0; i < path_map_local.GetCount(); i++) { + String lc = path_map_local[i]; + if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) + { + String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); + return slash ? UnixPath(r) : WinPath(r); + } + } + return slash ? UnixPath(path) : WinPath(path); +} + +String RemoteHost::GetLocalPath(const String& path) +{ + for(int i = 0; i < path_map_remote.GetCount(); i++) { + String rc = path_map_remote[i]; + if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) + return path_map_local[i] + path.Mid(rc.GetLength()); + } + if(!memcmp(path, "/cygdrive/", 10)) + { + const char *s = path.Begin() + 10; + String out; + if(*s) + out << *s++ << ':'; + out << s; + return out; + } + return NativePath(path); +} + +String RemoteHost::NormalizePath(const String& path) +{ + return path; +} + +String RemoteHost::RemoteExec(String cmd) +{ + Socket socket; + String sockerr; +/* + String hostname = host; + int port = 2346; + int ppos = hostname.Find(':'); + if(ppos >= 0) + { + port = atoi(host.GetIter(ppos + 1)); + hostname.Trim(ppos); + } +*/ + if(!ClientSocket(socket, host, port, true, NULL, 2000)) { + PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); + return String::GetVoid(); + } + socket.Write(cmd); + socket.Write("\0", 1); + return socket.ReadUntil('\0', Null, 10000000); +} + +Vector RemoteHost::GetFileInfo(const Vector& path) +{ + VectorMap out; + out.Reserve(path.GetCount()); + String request; + request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; + for(int i = 0; i < path.GetCount(); i++) + { + String hp = GetHostPath(path[i]); + request << hp << "\n"; + FileInfo& fi = out.Add(hp); + (Time&)fi = Time::Low(); + fi.length = Null; + } + String result = RemoteExec(request); + const char *p = result; + while(*p) + { + const char *b = p; + while(*p && *p != '\n' && *p != '\t') + p++; + String fn(b, p); + Time time = Time::Low(); + int size = Null; + if(*p == '\t') + { + int t = ScanInt(p + 1, &p); + if(!IsNull(t)) + time = TimeBase() + t; + if(*p == '\t') + size = ScanInt(p + 1, &p); + } + int ifn = out.Find(fn); + if(ifn >= 0) + { + (Time&)out[ifn] = time; + out[ifn].length = size; + } + while(*p && *p++ != '\n') + ; + } + return out.PickValues(); +} + +void RemoteHost::DeleteFile(const Vector& path) +{ + String request = "-"; + for(int i = 0; i < path.GetCount(); i++) + request << GetHostPath(path[i]) << "\n"; + String out = RemoteExec(request); + if(!IsNull(out) && out != "OK") + PutVerbose(out); +} + +void RemoteHost::DeleteFolderDeep(const String& folder) +{ + String out = RemoteExec("~" + GetHostPath(folder)); + if(out != "OK") + PutConsole(out); +} + +void RemoteHost::ChDir(const String& path) +{ + chdir_path = GetHostPath(path); +} + +void RemoteHost::RealizeDir(const String& path) +{ + RemoteExec("*" + GetHostPath(path)); +} + +void RemoteHost::SaveFile(const String& path, const String& data) +{ + String request; + request << ">" << GetHostPath(path) + << "\t" << int(GetSysTime() - TimeBase()) + << "\t" << data.GetLength() + << "\t" << ASCII85Encode(BZ2Compress(data)) + << "\n"; + String out = RemoteExec(request); + if(out != "OK") + PutConsole(out); +} + +String RemoteHost::LoadFile(const String& path) +{ + String hpath = GetHostPath(path); + String request = "^" + hpath; + String out = RemoteExec(request); + const char *p = out; + while(*p && *p != '\n' && *p != '\t') + p++; + if(*p++ != '\t') + return String::GetVoid(); + int len = ScanInt(p, &p); + if(IsNull(len) || len <= 0 || *p++ != '\t') + return String::GetVoid(); + String data = BZ2Decompress(ASCII85Decode(p)); + if(data.GetLength() != len) + { + PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", + hpath, data.GetLength(), len)); + return String::GetVoid(); + } + return data; +} + +int RemoteHost::Execute(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::ExecuteWithInput(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::Execute(const char *cmdline, Stream& out) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); +} + +bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); +} + +bool RemoteHost::Wait() +{ + return IdeConsoleWait(); +} + +One RemoteHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); + } + catch(...) { + return NULL; + } +} + +void RemoteHost::Launch(const char *_cmdline, bool) +{ +} + +void RemoteHost::AddFlags(Index& cfg) +{ + cfg.Add(os_type); +}