From 4c54893156cf2489081fe63eb37a0e4d3ede1e05 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Jan 2020 12:06:34 -0500 Subject: devdraw: do not force-hide menu and dock during full screen on mac This hides the menu on dock on all screens which is more than we want. The code was added to fix a problem with Catalina that I can no longer reproduce, so I guess it works now. Fixes #336. --- src/cmd/devdraw/mac-screen.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index e02a2524..5e23c43a 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -930,6 +930,13 @@ rpc_setmouse(Client *c, Point p) - (NSApplicationPresentationOptions)window:(id)arg willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions { + // The default for full-screen is to auto-hide the dock and menu bar, + // but the menu bar in particular comes back when the cursor is just + // near the top of the screen, which makes acme's top tag line very difficult to use. + // Disable the menu bar entirely. + // In theory this code disables the dock entirely too, but if you drag the mouse + // down far enough off the bottom of the screen the dock still unhides. + // That's OK. NSApplicationPresentationOptions o; o = proposedOptions; o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar); @@ -938,16 +945,21 @@ rpc_setmouse(Client *c, Point p) } - (void)windowWillEnterFullScreen:(NSNotification*)notification { - // TODO: This should only be done if the window - // is on the screen with the dock. - // But how can you tell which window has the dock? + // This is a heavier-weight way to make sure the menu bar and dock go away, + // but this affects all screens even though the app is running on full screen + // on only one screen, so it's not great. The behavior from the + // willUseFullScreenPresentationOptions seems to be enough for now. + /* [[NSApplication sharedApplication] setPresentationOptions:NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock]; + */ } - (void)windowDidExitFullScreen:(NSNotification*)notification { + /* [[NSApplication sharedApplication] setPresentationOptions:NSApplicationPresentationDefault]; + */ } @end -- cgit v1.2.3 From a0691bc460cbef889d017a640034f3321bd36b9d Mon Sep 17 00:00:00 2001 From: phonologus <59876118+phonologus@users.noreply.github.com> Date: Tue, 14 Jan 2020 19:52:18 +0000 Subject: tar: remove /bin/ when invoking compressors --- src/cmd/tar.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/tar.c b/src/cmd/tar.c index 61e9c4a6..6698675e 100644 --- a/src/cmd/tar.c +++ b/src/cmd/tar.c @@ -179,7 +179,6 @@ static int push(int fd, char *cmd, int input, Pushstate *ps) { int nfd, pifds[2]; - String *s; ps->open = 0; ps->fd = fd; @@ -197,11 +196,7 @@ push(int fd, char *cmd, int input, Pushstate *ps) dup(pifds[Rd], Stdin); close(pifds[input? Rd: Wr]); dup(fd, (input? Stdin: Stdout)); - s = s_new(); - if (cmd[0] != '/') - s_append(s, "/bin/"); - s_append(s, cmd); - execl(s_to_c(s), cmd, nil); + execl(cmd, cmd, nil); sysfatal("can't exec %s: %r", cmd); default: nfd = pifds[input? Rd: Wr]; -- cgit v1.2.3 From d28913a9e6609fef96f5baf6e9f4d5055ede744c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Jan 2020 16:38:34 -0500 Subject: acme: save/restore multiline tags in Dump/Load The dump substitutes each \n in a multiline tag with a 0xff byte. Since it is not valid UTF it cannot occur in an ordinary dump file. Old acmes will just read it in as an error rune. Fixes #135. Fixes #153. --- src/cmd/acme/rows.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/acme/rows.c b/src/cmd/acme/rows.c index 83c64594..7a64fabf 100644 --- a/src/cmd/acme/rows.c +++ b/src/cmd/acme/rows.c @@ -316,7 +316,7 @@ rowclean(Row *row) void rowdump(Row *row, char *file) { - int i, j, fd, m, n, dumped; + int i, j, fd, m, n, start, dumped; uint q0, q1; Biobuf *b; char *buf, *a, *fontname; @@ -434,9 +434,17 @@ rowdump(Row *row, char *file) m = min(RBUFSIZE, w->tag.file->b.nc); bufread(&w->tag.file->b, 0, r, m); n = 0; - while(nfile->b.nc; @@ -719,6 +727,10 @@ rowload(Row *row, char *file, int initing) if(l == nil) goto Rescue2; l[Blinelen(b)-1] = 0; + /* convert 0xff in multiline tag back to \n */ + for(i = 0; l[i] != 0; i++) + if((uchar)l[i] == 0xff) + l[i] = '\n'; r = bytetorune(l+5*12, &nr); ns = -1; for(n=0; n Date: Tue, 14 Jan 2020 19:43:32 -0500 Subject: devdraw: notify window resize promptly on x11 Fixes #339. --- src/cmd/devdraw/devdraw.c | 5 +---- src/cmd/devdraw/devdraw.h | 1 + src/cmd/devdraw/mac-screen.m | 1 - src/cmd/devdraw/srv.c | 18 ++++++++++++++++++ src/cmd/devdraw/x11-screen.c | 16 ++++++++-------- 5 files changed, 28 insertions(+), 13 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/devdraw.c b/src/cmd/devdraw/devdraw.c index 086574ef..b4c373ad 100644 --- a/src/cmd/devdraw/devdraw.c +++ b/src/cmd/devdraw/devdraw.c @@ -55,10 +55,7 @@ gfx_replacescreenimage(Client *c, Memimage *m) _freememimage(om); } qunlock(&c->drawlk); - - qlock(&c->eventlk); - c->mouse.resized = 1; - qunlock(&c->eventlk); + gfx_mouseresized(c); } static void diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h index 4980ed90..6829ab32 100644 --- a/src/cmd/devdraw/devdraw.h +++ b/src/cmd/devdraw/devdraw.h @@ -187,6 +187,7 @@ void gfx_keystroke(Client*, int); void gfx_main(void); void gfx_mousetrack(Client*, int, int, int, uint); void gfx_replacescreenimage(Client*, Memimage*); +void gfx_mouseresized(Client*); void gfx_started(void); // rpc_* routines are called on the RPC thread, diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index 5e23c43a..4bc3f088 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -518,7 +518,6 @@ rpc_resizeimg(Client *c) - (void)resizeimg { [self initimg]; gfx_replacescreenimage(self.client, self.img); - [self sendmouse:0]; } - (void)windowDidResize:(NSNotification *)notification { diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c index bfeb7c38..c98a865f 100644 --- a/src/cmd/devdraw/srv.c +++ b/src/cmd/devdraw/srv.c @@ -394,12 +394,30 @@ matchmouse(Client *c) } } +void +gfx_mouseresized(Client *c) +{ + gfx_mousetrack(c, -1, -1, -1, -1); +} + void gfx_mousetrack(Client *c, int x, int y, int b, uint ms) { Mouse *m; qlock(&c->eventlk); + if(x == -1 && y == -1 && b == -1 && ms == -1) { + Mouse *copy; + // repeat last mouse event for resize + if(c->mouse.ri == 0) + copy = &c->mouse.m[nelem(c->mouse.m)-1]; + else + copy = &c->mouse.m[c->mouse.ri-1]; + x = copy->xy.x; + y = copy->xy.y; + b = copy->buttons; + ms = copy->msec; + } if(x < c->mouserect.min.x) x = c->mouserect.min.x; if(x > c->mouserect.max.x) diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c index 8026e1e6..c3a6fa33 100644 --- a/src/cmd/devdraw/x11-screen.c +++ b/src/cmd/devdraw/x11-screen.c @@ -44,7 +44,7 @@ static Xwin* newxwin(Client *c) { Xwin *w; - + w = mallocz(sizeof *w, 1); if(w == nil) sysfatal("out of memory"); @@ -59,7 +59,7 @@ static Xwin* findxwin(XDrawable d) { Xwin *w, **l; - + for(l=&_x.windows; (w=*l) != nil; l=&w->next) { if(w->drawable == d) { /* move to front */ @@ -658,7 +658,7 @@ xattach(Client *client, char *label, char *winsize) _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False); _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False); } - + atoms[0] = _x.takefocus; atoms[1] = _x.losefocus; XChangeProperty(_x.display, w->drawable, _x.wmprotos, XA_ATOM, 32, @@ -700,7 +700,7 @@ xattach(Client *client, char *label, char *winsize) _x.gcsimplesrc = xgc(w->screenpm, FillStippled, -1); _x.gczero = xgc(w->screenpm, -1, -1); _x.gcreplsrc = xgc(w->screenpm, FillTiled, -1); - + pmid = XCreatePixmap(_x.display, w->drawable, 1, 1, 1); _x.gcfill0 = xgc(pmid, FillSolid, 0); _x.gccopy0 = xgc(pmid, -1, -1); @@ -729,7 +729,7 @@ rpc_setlabel(Client *client, char *label) { Xwin *w = (Xwin*)client->view; XTextProperty name; - + /* * Label and other properties required by ICCCCM. */ @@ -1032,7 +1032,7 @@ _xreplacescreenimage(Client *client) XDrawable pixmap; Rectangle r; Xwin *w; - + w = (Xwin*)client->view; r = w->newscreenr; pixmap = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth); @@ -1527,7 +1527,7 @@ __xputsnarf(char *data) { XButtonEvent e; Xwin *w; - + if(strlen(data) >= SnarfSize) return; qlock(&clip.lk); @@ -1730,7 +1730,7 @@ rpc_bouncemouse(Client *c, Mouse m) Xwin *w = (Xwin*)c->view; XButtonEvent e; XWindow dw; - + xlock(); e.type = ButtonPress; e.state = 0; -- cgit v1.2.3 From 5c06214952017d03f5e36bd1fbf25c1969922d80 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Jan 2020 19:46:47 -0500 Subject: venti/buildindex: fix hang on large indexes Fixes #93. --- src/cmd/venti/srv/buildindex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cmd') diff --git a/src/cmd/venti/srv/buildindex.c b/src/cmd/venti/srv/buildindex.c index faf4b414..540f0fdc 100644 --- a/src/cmd/venti/srv/buildindex.c +++ b/src/cmd/venti/srv/buildindex.c @@ -164,7 +164,7 @@ threadmain(int argc, char *argv[]) } /* wait for arena procs to finish */ - for(nfinish=0; nfinish Date: Wed, 15 Jan 2020 10:57:41 +0300 Subject: 9pfuse: update errortab --- src/cmd/9pfuse/errstr.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/cmd') diff --git a/src/cmd/9pfuse/errstr.c b/src/cmd/9pfuse/errstr.c index e3a122e4..ef5da00f 100644 --- a/src/cmd/9pfuse/errstr.c +++ b/src/cmd/9pfuse/errstr.c @@ -21,6 +21,7 @@ static Error errortab[] = { { "exist", ENOENT }, { "no such", ENOENT }, { "not found", ENOENT }, + { "not implemented", ENOSYS}, { "input/output", EIO }, { "timeout", ETIMEDOUT }, { "timed out", ETIMEDOUT }, @@ -42,6 +43,7 @@ static Error errortab[] = { { "invalid", EINVAL }, { "read-only", EROFS }, { "read only", EROFS }, + { "stale ", ESTALE}, #ifdef EPROTO { "proto", EPROTO }, #else -- cgit v1.2.3 From a9b462061c05f8cd4e1f85b05522770293c8a468 Mon Sep 17 00:00:00 2001 From: markvanatten Date: Wed, 15 Jan 2020 14:43:01 +0100 Subject: winwatch: port based Plan 9 winwatch Port of Plan 9's winwatch(1). --- src/cmd/rio/mkfile | 2 +- src/cmd/rio/winwatch.c | 538 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 src/cmd/rio/winwatch.c (limited to 'src/cmd') diff --git a/src/cmd/rio/mkfile b/src/cmd/rio/mkfile index 8b8ea46a..20202e22 100644 --- a/src/cmd/rio/mkfile +++ b/src/cmd/rio/mkfile @@ -16,7 +16,7 @@ RIOFILES=\ CFLAGS=$CFLAGS -DDEBUG HFILES=dat.h fns.h -TARG=rio xshove +TARG=rio winwatch xshove # need to add lib64 when it exists (on x86-64), but # Darwin complains about the nonexistant directory diff --git a/src/cmd/rio/winwatch.c b/src/cmd/rio/winwatch.c new file mode 100644 index 00000000..66ec8cbe --- /dev/null +++ b/src/cmd/rio/winwatch.c @@ -0,0 +1,538 @@ +/* slightly modified from +https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c +so as to deal with memory leaks and certain X errors */ + +#include +#include +#include +#include +#include +#include +#include "../devdraw/x11-inc.h" + +AUTOLIB(X11); + +typedef struct Win Win; +struct Win { + XWindow n; + int dirty; + char *label; + Rectangle r; +}; + +XDisplay *dpy; +XWindow root; +Atom net_active_window; +Reprog *exclude = nil; +Win *win; +int nwin; +int mwin; +int onwin; +int rows, cols; +int sortlabels; +int showwmnames; +Font *font; +Image *lightblue; + +XErrorHandler oldxerrorhandler; + +enum { + PAD = 3, + MARGIN = 5 +}; + +static jmp_buf savebuf; + +int +winwatchxerrorhandler(XDisplay *disp, XErrorEvent *xe) +{ + char buf[100]; + + XGetErrorText(disp, xe->error_code, buf, 100); + fprintf(stderr, "winwatch: X error %s, request code %d\n", buf, + xe->request_code); + XFlush(disp); + XSync(disp, False); + XSetErrorHandler(oldxerrorhandler); + longjmp(savebuf, 1); +} + +void* +erealloc(void *v, ulong n) +{ + v = realloc(v, n); + if (v == nil) + sysfatal("out of memory reallocating"); + return v; +} + +char* +estrdup(char *s) +{ + s = strdup(s); + if (s == nil) + sysfatal("out of memory allocating"); + return s; +} + +char* +getproperty(XWindow w, Atom a) +{ + uchar *p; + int fmt; + Atom type; + ulong n, dummy; + int s; + + n = 100; + p = nil; + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XGetWindowProperty(dpy, w, a, 0, 100L, 0, + AnyPropertyType, &type, &fmt, &n, &dummy, &p); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + + if (s == 0) + return (char *) p; + else { + free(p); + return nil; + } +} + +XWindow +findname(XWindow w) +{ + int i; + uint nxwin; + XWindow dw1, dw2, *xwin; + char *p; + int s; + Atom net_wm_name; + + p = getproperty(w, XA_WM_NAME); + if (p) { + free(p); + return w; + } + + net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); + p = getproperty(w, net_wm_name); + if (p) { + free(p); + return w; + } + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + if (s == 0) { + if (xwin != NULL) + XFree(xwin); + return 0; + } + + for (i = 0; i < nxwin; i++) { + w = findname(xwin[i]); + if (w != 0) { + XFree(xwin); + return w; + } + } + + XFree(xwin); + + return 0; +} + +int +wcmp(const void *w1, const void *w2) +{ + return *(XWindow *) w1 - *(XWindow *) w2; +} + +/* unicode-aware case-insensitive strcmp, taken from golang’s gc/subr.c */ + +int +_cistrcmp(char *p, char *q) +{ + Rune rp, rq; + + while(*p || *q) { + if(*p == 0) + return +1; + if(*q == 0) + return -1; + p += chartorune(&rp, p); + q += chartorune(&rq, q); + rp = tolowerrune(rp); + rq = tolowerrune(rq); + if(rp < rq) + return -1; + if(rp > rq) + return +1; + } + return 0; +} + +int +winlabelcmp(const void *w1, const void *w2) +{ + const Win *p1 = (Win *) w1; + const Win *p2 = (Win *) w2; + return _cistrcmp(p1->label, p2->label); +} + +void +refreshwin(void) +{ + XWindow dw1, dw2, *xwin; + XClassHint class; + XWindowAttributes attr; + char *label; + char *wmname; + int i, nw; + uint nxwin; + Status s; + Atom net_wm_name; + + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + if (s == 0) { + if (xwin != NULL) + XFree(xwin); + return; + } + qsort(xwin, nxwin, sizeof(xwin[0]), wcmp); + + nw = 0; + for (i = 0; i < nxwin; i++) { + memset(&attr, 0, sizeof attr); + xwin[i] = findname(xwin[i]); + if (xwin[i] == 0) + continue; + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XGetWindowAttributes(dpy, xwin[i], &attr); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + if (s == 0) + continue; + if (attr.width <= 0 || attr.override_redirect + || attr.map_state != IsViewable) + continue; + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XGetClassHint(dpy, xwin[i], &class); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + if (s == 0) + continue; + + if (exclude != nil && regexec(exclude, class.res_name, nil, 0)) { + free(class.res_name); + free(class.res_class); + continue; + } + + net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); + wmname = getproperty(xwin[i], net_wm_name); + + if (wmname == nil) { + wmname = getproperty(xwin[i], XA_WM_NAME); + if (wmname == nil) { + free(class.res_name); + free(class.res_class); + continue; + } + } + + if (showwmnames == 1) + label = wmname; + else + label = class.res_name; + + if (nw < nwin && win[nw].n == xwin[i] + && strcmp(win[nw].label, label) == 0) { + nw++; + free(wmname); + free(class.res_name); + free(class.res_class); + continue; + } + + if (nw < nwin) { + free(win[nw].label); + win[nw].label = nil; + } + + if (nw >= mwin) { + mwin += 8; + win = erealloc(win, mwin * sizeof(win[0])); + } + win[nw].n = xwin[i]; + win[nw].label = estrdup(label); + win[nw].dirty = 1; + win[nw].r = Rect(0, 0, 0, 0); + free(wmname); + free(class.res_name); + free(class.res_class); + nw++; + } + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + XFree(xwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + while (nwin > nw) + free(win[--nwin].label); + nwin = nw; + + if (sortlabels == 1) + qsort(win, nwin, sizeof(struct Win), winlabelcmp); + + return; +} + +void +drawnowin(int i) +{ + Rectangle r; + + r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, + font->height); + r = rectaddpt(rectaddpt + (r, + Pt(MARGIN + (PAD + Dx(r)) * (i / rows), + MARGIN + (PAD + Dy(r)) * (i % rows))), + screen->r.min); + draw(screen, insetrect(r, -1), lightblue, nil, ZP); +} + +void +drawwin(int i) +{ + draw(screen, win[i].r, lightblue, nil, ZP); + _string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP, + font, win[i].label, nil, strlen(win[i].label), + win[i].r, nil, ZP, SoverD); + border(screen, win[i].r, 1, display->black, ZP); + win[i].dirty = 0; +} + +int +geometry(void) +{ + int i, ncols, z; + Rectangle r; + + z = 0; + rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD); + if (rows * cols < nwin || rows * cols >= nwin * 2) { + ncols = nwin <= 0 ? 1 : (nwin + rows - 1) / rows; + if (ncols != cols) { + cols = ncols; + z = 1; + } + } + + r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, + font->height); + for (i = 0; i < nwin; i++) + win[i].r = + rectaddpt(rectaddpt + (r, + Pt(MARGIN + (PAD + Dx(r)) * (i / rows), + MARGIN + (PAD + Dy(r)) * (i % rows))), + screen->r.min); + + return z; +} + +void +redraw(Image *screen, int all) +{ + int i; + + all |= geometry(); + if (all) + draw(screen, screen->r, lightblue, nil, ZP); + for (i = 0; i < nwin; i++) + if (all || win[i].dirty) + drawwin(i); + if (!all) + for (; i < onwin; i++) + drawnowin(i); + + onwin = nwin; +} + +void +eresized(int new) +{ + if (new && getwindow(display, Refmesg) < 0) + fprint(2, "can't reattach to window"); + geometry(); + redraw(screen, 1); +} + + +void +selectwin(XWindow win) +{ + XEvent ev; + long mask; + + memset(&ev, 0, sizeof ev); + ev.xclient.type = ClientMessage; + ev.xclient.serial = 0; + ev.xclient.send_event = True; + ev.xclient.message_type = net_active_window; + ev.xclient.window = win; + ev.xclient.format = 32; + mask = SubstructureRedirectMask | SubstructureNotifyMask; + + XSendEvent(dpy, root, False, mask, &ev); + XMapRaised(dpy, win); + XSync(dpy, False); +} + + +void +click(Mouse m) +{ + int i, j; + + if (m.buttons == 0 || (m.buttons & ~4)) + return; + + for (i = 0; i < nwin; i++) + if (ptinrect(m.xy, win[i].r)) + break; + if (i == nwin) + return; + + do + m = emouse(); + while (m.buttons == 4); + + if (m.buttons != 0) { + do + m = emouse(); + while (m.buttons); + return; + } + + for (j = 0; j < nwin; j++) + if (ptinrect(m.xy, win[j].r)) + break; + if (j != i) + return; + + selectwin(win[i].n); +} + +void +usage(void) +{ + fprint(2, + "usage: winwatch [-e exclude] [-W winsize] [-f font] [-n] [-s]\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + char *fontname; + int Etimer; + Event e; + + sortlabels = 0; + showwmnames = 0; + + fontname = "/lib/font/bit/lucsans/unicode.8.font"; + + ARGBEGIN { + case 'W': + winsize = EARGF(usage()); + break; + case 'f': + fontname = EARGF(usage()); + break; + case 'e': + exclude = regcomp(EARGF(usage())); + if (exclude == nil) + sysfatal("Bad regexp"); + break; + case 's': + sortlabels = 1; + break; + case 'n': + showwmnames = 1; + break; + default: + usage(); + } + ARGEND if (argc) + usage(); + + /* moved up from original winwatch.c for p9p because there can be only one but we want to restart when needed */ + einit(Emouse | Ekeyboard); + Etimer = etimer(0, 1000); + + dpy = XOpenDisplay(""); + + if (dpy == nil) + sysfatal("open display: %r"); + + root = DefaultRootWindow(dpy); + net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + + initdraw(0, 0, "winwatch"); + lightblue = allocimagemix(display, DPalebluegreen, DWhite); + if (lightblue == nil) + sysfatal("allocimagemix: %r"); + if ((font = openfont(display, fontname)) == nil) + sysfatal("font '%s' not found", fontname); + + + /* reentry point upon X server errors */ + setjmp(savebuf); + + refreshwin(); + redraw(screen, 1); + + for (;;) { + switch (eread(Emouse | Ekeyboard | Etimer, &e)) { + case Ekeyboard: + if (e.kbdc == 0x7F || e.kbdc == 'q') + exits(0); + break; + case Emouse: + if (e.mouse.buttons) + click(e.mouse); + /* fall through */ + default: /* Etimer */ + refreshwin(); + redraw(screen, 0); + break; + } + } +} -- cgit v1.2.3 From 0ac4bfee32fce9dc336751aa219ca4dbdf3e8ecd Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Wed, 15 Jan 2020 14:15:31 +0000 Subject: clock: Remove unused static variable in clock.c `struct Tm tms` was set but never referenced; noticed in a compiler warning. Remove it. Signed-off-by: Dan Cross --- src/cmd/draw/clock.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/draw/clock.c b/src/cmd/draw/clock.c index b804e1f4..b5d028b6 100644 --- a/src/cmd/draw/clock.c +++ b/src/cmd/draw/clock.c @@ -25,7 +25,6 @@ redraw(Image *screen) static int rad; int i; int anghr, angmin; - static Tm tms; static Tm ntms; ntm = time(0); @@ -36,7 +35,6 @@ redraw(Image *screen) anghr = 90-(ntms.hour*5 + ntms.min/12)*6; angmin = 90-ntms.min*6; tm = ntm; - tms = ntms; r = screen->r; c = divpt(addpt(r.min, r.max), 2); rad = Dx(r) < Dy(r) ? Dx(r) : Dy(r); -- cgit v1.2.3 From 6510a2d3530132753a6a1dfb2589e9ad82bc271c Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Wed, 15 Jan 2020 14:47:39 +0000 Subject: winwatch: Plan 9-ify. This is new code, and custom to plan9port. Make it conform more closely to plan9 style. Signed-off-by: Dan Cross --- src/cmd/rio/winwatch.c | 838 ++++++++++++++++++++++++------------------------- 1 file changed, 412 insertions(+), 426 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/rio/winwatch.c b/src/cmd/rio/winwatch.c index 66ec8cbe..1a93e78c 100644 --- a/src/cmd/rio/winwatch.c +++ b/src/cmd/rio/winwatch.c @@ -1,23 +1,25 @@ -/* slightly modified from -https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c -so as to deal with memory leaks and certain X errors */ +/* + * slightly modified from + * https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c + * so as to deal with memory leaks and certain X errors + */ #include #include #include #include #include -#include +#include #include "../devdraw/x11-inc.h" AUTOLIB(X11); typedef struct Win Win; struct Win { - XWindow n; - int dirty; - char *label; - Rectangle r; + XWindow n; + int dirty; + char *label; + Rectangle r; }; XDisplay *dpy; @@ -37,502 +39,486 @@ Image *lightblue; XErrorHandler oldxerrorhandler; enum { - PAD = 3, - MARGIN = 5 + PAD = 3, + MARGIN = 5 }; static jmp_buf savebuf; -int +int winwatchxerrorhandler(XDisplay *disp, XErrorEvent *xe) { - char buf[100]; - - XGetErrorText(disp, xe->error_code, buf, 100); - fprintf(stderr, "winwatch: X error %s, request code %d\n", buf, - xe->request_code); - XFlush(disp); - XSync(disp, False); - XSetErrorHandler(oldxerrorhandler); - longjmp(savebuf, 1); + char buf[100]; + + XGetErrorText(disp, xe->error_code, buf, 100); + fprint(2, "winwatch: X error %s, request code %d\n", + buf, xe->request_code); + XFlush(disp); + XSync(disp, False); + XSetErrorHandler(oldxerrorhandler); + longjmp(savebuf, 1); + return(0); /* Not reached */ } void* erealloc(void *v, ulong n) { - v = realloc(v, n); - if (v == nil) - sysfatal("out of memory reallocating"); - return v; + v = realloc(v, n); + if(v==nil) + sysfatal("out of memory reallocating"); + return v; } char* estrdup(char *s) { - s = strdup(s); - if (s == nil) - sysfatal("out of memory allocating"); - return s; + s = strdup(s); + if(s==nil) + sysfatal("out of memory allocating"); + return(s); } char* getproperty(XWindow w, Atom a) { - uchar *p; - int fmt; - Atom type; - ulong n, dummy; - int s; - - n = 100; - p = nil; - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - s = XGetWindowProperty(dpy, w, a, 0, 100L, 0, - AnyPropertyType, &type, &fmt, &n, &dummy, &p); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - - if (s == 0) - return (char *) p; - else { - free(p); - return nil; - } + uchar *p; + int fmt; + Atom type; + ulong n, dummy; + int s; + + n = 100; + p = nil; + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XGetWindowProperty(dpy, w, a, 0, 100L, 0, + AnyPropertyType, &type, &fmt, &n, &dummy, &p); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + if(s!=0){ + XFree(p); + return(nil); + } + + return((char*)p); } -XWindow +XWindow findname(XWindow w) { - int i; - uint nxwin; - XWindow dw1, dw2, *xwin; - char *p; - int s; - Atom net_wm_name; - - p = getproperty(w, XA_WM_NAME); - if (p) { - free(p); - return w; - } - - net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); - p = getproperty(w, net_wm_name); - if (p) { - free(p); - return w; - } - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - if (s == 0) { - if (xwin != NULL) - XFree(xwin); - return 0; - } - - for (i = 0; i < nxwin; i++) { - w = findname(xwin[i]); - if (w != 0) { - XFree(xwin); - return w; - } - } - - XFree(xwin); - - return 0; + int i; + uint nxwin; + XWindow dw1, dw2, *xwin; + char *p; + int s; + Atom net_wm_name; + + p = getproperty(w, XA_WM_NAME); + if(p){ + free(p); + return(w); + } + + net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", FALSE); + p = getproperty(w, net_wm_name); + if(p){ + free(p); + return(w); + } + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + if(s == 0) { + if (xwin != NULL) + XFree(xwin); + return 0; + } + + for (i = 0; i < nxwin; i++) { + w = findname(xwin[i]); + if (w != 0) { + XFree(xwin); + return w; + } + } + XFree(xwin); + + return 0; } -int +int wcmp(const void *w1, const void *w2) { - return *(XWindow *) w1 - *(XWindow *) w2; + return *(XWindow *) w1 - *(XWindow *) w2; } /* unicode-aware case-insensitive strcmp, taken from golang’s gc/subr.c */ -int +int _cistrcmp(char *p, char *q) { - Rune rp, rq; - - while(*p || *q) { - if(*p == 0) - return +1; - if(*q == 0) - return -1; - p += chartorune(&rp, p); - q += chartorune(&rq, q); - rp = tolowerrune(rp); - rq = tolowerrune(rq); - if(rp < rq) - return -1; - if(rp > rq) - return +1; - } - return 0; + Rune rp, rq; + + while(*p || *q) { + if(*p == 0) + return +1; + if(*q == 0) + return -1; + p += chartorune(&rp, p); + q += chartorune(&rq, q); + rp = tolowerrune(rp); + rq = tolowerrune(rq); + if(rp < rq) + return -1; + if(rp > rq) + return +1; + } + return 0; } -int +int winlabelcmp(const void *w1, const void *w2) { - const Win *p1 = (Win *) w1; - const Win *p2 = (Win *) w2; - return _cistrcmp(p1->label, p2->label); + const Win *p1 = (Win *) w1; + const Win *p2 = (Win *) w2; + return _cistrcmp(p1->label, p2->label); } -void +void refreshwin(void) { - XWindow dw1, dw2, *xwin; - XClassHint class; - XWindowAttributes attr; - char *label; - char *wmname; - int i, nw; - uint nxwin; - Status s; - Atom net_wm_name; - - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - if (s == 0) { - if (xwin != NULL) - XFree(xwin); - return; - } - qsort(xwin, nxwin, sizeof(xwin[0]), wcmp); - - nw = 0; - for (i = 0; i < nxwin; i++) { - memset(&attr, 0, sizeof attr); - xwin[i] = findname(xwin[i]); - if (xwin[i] == 0) - continue; - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - s = XGetWindowAttributes(dpy, xwin[i], &attr); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - if (s == 0) - continue; - if (attr.width <= 0 || attr.override_redirect - || attr.map_state != IsViewable) - continue; - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - s = XGetClassHint(dpy, xwin[i], &class); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - if (s == 0) - continue; - - if (exclude != nil && regexec(exclude, class.res_name, nil, 0)) { - free(class.res_name); - free(class.res_class); - continue; - } - - net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); - wmname = getproperty(xwin[i], net_wm_name); - - if (wmname == nil) { - wmname = getproperty(xwin[i], XA_WM_NAME); - if (wmname == nil) { - free(class.res_name); - free(class.res_class); - continue; - } - } - - if (showwmnames == 1) - label = wmname; - else - label = class.res_name; - - if (nw < nwin && win[nw].n == xwin[i] - && strcmp(win[nw].label, label) == 0) { - nw++; - free(wmname); - free(class.res_name); - free(class.res_class); - continue; - } - - if (nw < nwin) { - free(win[nw].label); - win[nw].label = nil; - } - - if (nw >= mwin) { - mwin += 8; - win = erealloc(win, mwin * sizeof(win[0])); - } - win[nw].n = xwin[i]; - win[nw].label = estrdup(label); - win[nw].dirty = 1; - win[nw].r = Rect(0, 0, 0, 0); - free(wmname); - free(class.res_name); - free(class.res_class); - nw++; - } - - oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); - XFree(xwin); - XFlush(dpy); - XSync(dpy, False); - XSetErrorHandler(oldxerrorhandler); - - while (nwin > nw) - free(win[--nwin].label); - nwin = nw; - - if (sortlabels == 1) - qsort(win, nwin, sizeof(struct Win), winlabelcmp); - - return; + XWindow dw1, dw2, *xwin; + XClassHint class; + XWindowAttributes attr; + char *label; + char *wmname; + int i, nw; + uint nxwin; + Status s; + Atom net_wm_name; + + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + if(s==0){ + if(xwin!=NULL) + XFree(xwin); + return; + } + qsort(xwin, nxwin, sizeof(xwin[0]), wcmp); + + nw = 0; + for(i=0; i=mwin){ + mwin += 8; + win = erealloc(win, mwin * sizeof(win[0])); + } + win[nw].n = xwin[i]; + win[nw].label = estrdup(label); + win[nw].dirty = 1; + win[nw].r = Rect(0, 0, 0, 0); + free(wmname); + free(class.res_name); + free(class.res_class); + nw++; + } + + oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); + XFree(xwin); + XFlush(dpy); + XSync(dpy, False); + XSetErrorHandler(oldxerrorhandler); + + while(nwin>nw) + free(win[--nwin].label); + nwin = nw; + + if(sortlabels==1) + qsort(win, nwin, sizeof(struct Win), winlabelcmp); } -void +void drawnowin(int i) { - Rectangle r; - - r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, - font->height); - r = rectaddpt(rectaddpt - (r, - Pt(MARGIN + (PAD + Dx(r)) * (i / rows), - MARGIN + (PAD + Dy(r)) * (i % rows))), - screen->r.min); - draw(screen, insetrect(r, -1), lightblue, nil, ZP); + Rectangle r; + + r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height); + r = rectaddpt( + rectaddpt(r, + Pt(MARGIN + (PAD + Dx(r)) * (i / rows), + MARGIN + (PAD + Dy(r)) * (i % rows))), + screen->r.min); + draw(screen, insetrect(r, -1), lightblue, nil, ZP); } -void +void drawwin(int i) { - draw(screen, win[i].r, lightblue, nil, ZP); - _string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP, - font, win[i].label, nil, strlen(win[i].label), - win[i].r, nil, ZP, SoverD); - border(screen, win[i].r, 1, display->black, ZP); - win[i].dirty = 0; + draw(screen, win[i].r, lightblue, nil, ZP); + _string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP, + font, win[i].label, nil, strlen(win[i].label), + win[i].r, nil, ZP, SoverD); + border(screen, win[i].r, 1, display->black, ZP); + win[i].dirty = 0; } -int +int geometry(void) { - int i, ncols, z; - Rectangle r; - - z = 0; - rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD); - if (rows * cols < nwin || rows * cols >= nwin * 2) { - ncols = nwin <= 0 ? 1 : (nwin + rows - 1) / rows; - if (ncols != cols) { - cols = ncols; - z = 1; - } - } - - r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, - font->height); - for (i = 0; i < nwin; i++) - win[i].r = - rectaddpt(rectaddpt - (r, - Pt(MARGIN + (PAD + Dx(r)) * (i / rows), - MARGIN + (PAD + Dy(r)) * (i % rows))), - screen->r.min); - - return z; + int i, ncols, z; + Rectangle r; + + z = 0; + rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD); + if(rows*cols=nwin*2){ + ncols = 1; + if(nwin>0) + ncols = (nwin + rows - 1) / rows; + if(ncols!=cols){ + cols = ncols; + z = 1; + } + } + + r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height); + for(i=0; ir.min); + + return z; } -void +void redraw(Image *screen, int all) { - int i; - - all |= geometry(); - if (all) - draw(screen, screen->r, lightblue, nil, ZP); - for (i = 0; i < nwin; i++) - if (all || win[i].dirty) - drawwin(i); - if (!all) - for (; i < onwin; i++) - drawnowin(i); - - onwin = nwin; + int i; + + all |= geometry(); + if(all) + draw(screen, screen->r, lightblue, nil, ZP); + for(i=0; i Date: Wed, 15 Jan 2020 11:54:20 +0000 Subject: compress: import Plan9 compress Add #define USED(x)... boilerplate compress: import Plan9 manpage. --- src/cmd/compress/compress.c | 1274 +++++++++++++++++++++++++++++++++++++++++++ src/cmd/compress/mkfile | 15 + 2 files changed, 1289 insertions(+) create mode 100755 src/cmd/compress/compress.c create mode 100755 src/cmd/compress/mkfile (limited to 'src/cmd') diff --git a/src/cmd/compress/compress.c b/src/cmd/compress/compress.c new file mode 100755 index 00000000..808762ca --- /dev/null +++ b/src/cmd/compress/compress.c @@ -0,0 +1,1274 @@ +/* + * compress - File compression ala IEEE Computer, June 1984. + * + * Algorithm from "A Technique for High Performance Data Compression", + * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19. + * + * Usage: compress [-dfvc] [-b bits] [file ...] + * Inputs: + * -b: limit the max number of bits/code. + * -c: write output on stdout, don't remove original. + * -d: decompress instead. + * -f: Forces output file to be generated, even if one already + * exists, and even if no space is saved by compressing. + * If -f is not used, the user will be prompted if stdin is + * a tty, otherwise, the output file will not be overwritten. + * -v: Write compression statistics + * + * file ...: Files to be compressed. If none specified, stdin is used. + * Outputs: + * file.Z: Compressed form of file with same mode, owner, and utimes + * or stdout (if stdin used as input) + * + * Assumptions: + * When filenames are given, replaces with the compressed version + * (.Z suffix) only if the file decreases in size. + * Algorithm: + * Modified Lempel-Ziv method (LZW). Basically finds common + * substrings and replaces them with a variable size code. This is + * deterministic, and can be done on the fly. Thus, the decompression + * procedure needs no input table, but tracks the way the table was built. + + * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + */ + +#ifndef USED +# define USED(x) if(x);else +#endif + +#define _PLAN9_SOURCE +#define _BSD_EXTENSION +#define _POSIX_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define min(a,b) ((a>b) ? b : a) + +#define BITS 16 +#define HSIZE 69001 /* 95% occupancy */ + +/* + * a code_int must be able to hold 2**BITS values of type int, and also -1 + */ +typedef long code_int; +typedef long count_int; + +static char rcs_ident[] = "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $"; + +uchar magic_header[] = { 0x1F, 0x9D }; /* 1F 9D */ + +/* Defines for third byte of header */ +#define BIT_MASK 0x1f +#define BLOCK_MASK 0x80 +/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is + a fourth header byte (for expansion). +*/ +#define INIT_BITS 9 /* initial number of bits/code */ + +#define ARGVAL() (*++(*argv) || (--argc && *++argv)) + +int n_bits; /* number of bits/code */ +int maxbits = BITS; /* user settable max # bits/code */ +code_int maxcode; /* maximum code, given n_bits */ +code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */ + +#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) + +count_int htab[HSIZE]; +ushort codetab[HSIZE]; + +#define htabof(i) htab[i] +#define codetabof(i) codetab[i] + +code_int hsize = HSIZE; /* for dynamic table sizing */ +count_int fsize; + +/* + * To save much memory, we overlay the table used by compress() with those + * used by decompress(). The tab_prefix table is the same size and type + * as the codetab. The tab_suffix table needs 2**BITS characters. We + * get this from the beginning of htab. The output stack uses the rest + * of htab, and contains characters. There is plenty of room for any + * possible stack (stack used to be 8000 characters). + */ + +#define tab_prefixof(i) codetabof(i) +#define tab_suffixof(i) ((uchar *)(htab))[i] +#define de_stack ((uchar *)&tab_suffixof(1< 0; argc--, argv++) { + if (**argv == '-') { /* A flag argument */ + while (*++(*argv)) { /* Process all flags in this arg */ + switch (**argv) { + case 'C': + block_compress = 0; + break; +#ifdef DEBUG + case 'D': + debug = 1; + break; + case 'V': + verbose = 1; + version(); + break; +#else + case 'V': + version(); + break; +#endif + case 'b': + if (!ARGVAL()) { + fprintf(stderr, "Missing maxbits\n"); + Usage(); + exit(1); + } + maxbits = atoi(*argv); + goto nextarg; + case 'c': + zcat_flg = 1; + break; + case 'd': + do_decomp = 1; + break; + case 'f': + case 'F': + overwrite = 1; + force = 1; + break; + case 'n': + nomagic = 1; + break; + case 'q': + quiet = 1; + break; + case 'v': + quiet = 0; + break; + default: + fprintf(stderr, "Unknown flag: '%c'; ", **argv); + Usage(); + exit(1); + } + } + } else { /* Input file name */ + *fileptr++ = *argv; /* Build input file list */ + *fileptr = NULL; + /* process nextarg; */ + } +nextarg: + continue; + } + + if(maxbits < INIT_BITS) maxbits = INIT_BITS; + if (maxbits > BITS) maxbits = BITS; + maxmaxcode = 1 << maxbits; + + if (*filelist != NULL) { + for (fileptr = filelist; *fileptr; fileptr++) { + exit_stat = 0; + if (do_decomp != 0) { /* DECOMPRESSION */ + /* Check for .Z suffix */ + if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) { + /* No .Z: tack one on */ + strcpy(tempname, *fileptr); + strcat(tempname, ".Z"); + *fileptr = tempname; + } + /* Open input file */ + if ((freopen(*fileptr, "r", stdin)) == NULL) { + perror(*fileptr); + continue; + } + /* Check the magic number */ + if (nomagic == 0) { + if ((getchar() != (magic_header[0] & 0xFF)) + || (getchar() != (magic_header[1] & 0xFF))) { + fprintf(stderr, "%s: not in compressed format\n", + *fileptr); + continue; + } + maxbits = getchar(); /* set -b from file */ + block_compress = maxbits & BLOCK_MASK; + maxbits &= BIT_MASK; + maxmaxcode = 1 << maxbits; + if(maxbits > BITS) { + fprintf(stderr, + "%s: compressed with %d bits, can only handle %d bits\n", + *fileptr, maxbits, BITS); + continue; + } + } + /* Generate output filename */ + strcpy(ofname, *fileptr); + ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */ + } else { /* COMPRESSION */ + if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) { + fprintf(stderr, + "%s: already has .Z suffix -- no change\n", + *fileptr); + continue; + } + /* Open input file */ + if ((freopen(*fileptr, "r", stdin)) == NULL) { + perror(*fileptr); + continue; + } + (void) stat(*fileptr, &statbuf); + fsize = (long) statbuf.st_size; + /* + * tune hash table size for small files -- ad hoc, + * but the sizes match earlier #defines, which + * serve as upper bounds on the number of output codes. + */ + hsize = HSIZE; + if (fsize < (1 << 12)) + hsize = min(5003, HSIZE); + else if (fsize < (1 << 13)) + hsize = min(9001, HSIZE); + else if (fsize < (1 << 14)) + hsize = min (18013, HSIZE); + else if (fsize < (1 << 15)) + hsize = min (35023, HSIZE); + else if (fsize < 47000) + hsize = min (50021, HSIZE); + + /* Generate output filename */ + strcpy(ofname, *fileptr); +#ifndef BSD4_2 + if ((cp=strrchr(ofname,'/')) != NULL) + cp++; + else + cp = ofname; + /* + *** changed 12 to 25; should be NAMELEN-3, but I don't want + * to fight the headers. ehg 5 Nov 92 ** + */ + if (strlen(cp) > 25) { + fprintf(stderr, "%s: filename too long to tack on .Z\n", + cp); + continue; + } +#endif + strcat(ofname, ".Z"); + } + /* Check for overwrite of existing file */ + if (overwrite == 0 && zcat_flg == 0 && + stat(ofname, &statbuf) == 0) { + char response[2]; + + response[0] = 'n'; + fprintf(stderr, "%s already exists;", ofname); + if (foreground()) { + fprintf(stderr, + " do you wish to overwrite %s (y or n)? ", + ofname); + fflush(stderr); + (void) read(2, response, 2); + while (response[1] != '\n') + if (read(2, response+1, 1) < 0) { + /* Ack! */ + perror("stderr"); + break; + } + } + if (response[0] != 'y') { + fprintf(stderr, "\tnot overwritten\n"); + continue; + } + } + if(zcat_flg == 0) { /* Open output file */ + if (freopen(ofname, "w", stdout) == NULL) { + perror(ofname); + continue; + } + if(!quiet) + fprintf(stderr, "%s: ", *fileptr); + } + + /* Actually do the compression/decompression */ + if (do_decomp == 0) + compress(); +#ifndef DEBUG + else + decompress(); +#else + else if (debug == 0) + decompress(); + else + printcodes(); + if (verbose) + dump_tab(); +#endif /* DEBUG */ + if(zcat_flg == 0) { + copystat(*fileptr, ofname); /* Copy stats */ + if (exit_stat == 1 || !quiet) + putc('\n', stderr); + } + } + } else { /* Standard input */ + if (do_decomp == 0) { + compress(); +#ifdef DEBUG + if(verbose) + dump_tab(); +#endif + if(!quiet) + putc('\n', stderr); + } else { + /* Check the magic number */ + if (nomagic == 0) { + if ((getchar()!=(magic_header[0] & 0xFF)) + || (getchar()!=(magic_header[1] & 0xFF))) { + fprintf(stderr, "stdin: not in compressed format\n"); + exit(1); + } + maxbits = getchar(); /* set -b from file */ + block_compress = maxbits & BLOCK_MASK; + maxbits &= BIT_MASK; + maxmaxcode = 1 << maxbits; + fsize = 100000; /* assume stdin large for USERMEM */ + if(maxbits > BITS) { + fprintf(stderr, + "stdin: compressed with %d bits, can only handle %d bits\n", + maxbits, BITS); + exit(1); + } + } +#ifndef DEBUG + decompress(); +#else + if (debug == 0) + decompress(); + else + printcodes(); + if (verbose) + dump_tab(); +#endif /* DEBUG */ + } + } + exit(exit_stat); + return 0; +} + +static int offset; +long in_count = 1; /* length of input */ +long bytes_out; /* length of compressed output */ +long out_count = 0; /* # of codes output (for debugging) */ + +/* + * compress stdin to stdout + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / next character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. Here, the modular division first probe is gives way + * to a faster exclusive-or manipulation. Also do block compression with + * an adaptive reset, whereby the code table is cleared when the compression + * ratio decreases, but after the table fills. The variable-length output + * codes are re-sized at this point, and a special CLEAR code is generated + * for the decompressor. Late addition: construct the table according to + * file size for noticeable speed improvement on small files. Please direct + * questions about this implementation to ames!jaw. + */ +void +compress(void) +{ + code_int ent, hsize_reg; + code_int i; + int c, disp, hshift; + long fcode; + + if (nomagic == 0) { + putchar(magic_header[0]); + putchar(magic_header[1]); + putchar((char)(maxbits | block_compress)); + if(ferror(stdout)) + writeerr(); + } + offset = 0; + bytes_out = 3; /* includes 3-byte header mojo */ + out_count = 0; + clear_flg = 0; + ratio = 0; + in_count = 1; + checkpoint = CHECK_GAP; + maxcode = MAXCODE(n_bits = INIT_BITS); + free_ent = (block_compress? FIRST: 256); + + ent = getchar (); + + hshift = 0; + for (fcode = (long)hsize; fcode < 65536L; fcode *= 2) + hshift++; + hshift = 8 - hshift; /* set hash code range bound */ + + hsize_reg = hsize; + cl_hash( (count_int) hsize_reg); /* clear hash table */ + + while ((c = getchar()) != EOF) { + in_count++; + fcode = (long) (((long) c << maxbits) + ent); + i = ((c << hshift) ^ ent); /* xor hashing */ + + if (htabof (i) == fcode) { + ent = codetabof(i); + continue; + } else if ((long)htabof(i) < 0 ) /* empty slot */ + goto nomatch; + disp = hsize_reg - i; /* secondary hash (after G. Knott) */ + if (i == 0) + disp = 1; +probe: + if ((i -= disp) < 0) + i += hsize_reg; + + if (htabof (i) == fcode) { + ent = codetabof(i); + continue; + } + if ((long)htabof(i) > 0) + goto probe; +nomatch: + output((code_int)ent); + out_count++; + ent = c; + if (free_ent < maxmaxcode) { + codetabof(i) = free_ent++; /* code -> hashtable */ + htabof(i) = fcode; + } else if ((count_int)in_count >= checkpoint && block_compress) + cl_block (); + } + /* + * Put out the final code. + */ + output( (code_int)ent ); + out_count++; + output( (code_int)-1 ); + + /* + * Print out stats on stderr + */ + if(zcat_flg == 0 && !quiet) { +#ifdef DEBUG + fprintf( stderr, + "%ld chars in, %ld codes (%ld bytes) out, compression factor: ", + in_count, out_count, bytes_out ); + prratio( stderr, in_count, bytes_out ); + fprintf( stderr, "\n"); + fprintf( stderr, "\tCompression as in compact: " ); + prratio( stderr, in_count-bytes_out, in_count ); + fprintf( stderr, "\n"); + fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", + free_ent - 1, n_bits ); +#else /* !DEBUG */ + fprintf( stderr, "Compression: " ); + prratio( stderr, in_count-bytes_out, in_count ); +#endif /* DEBUG */ + } + if(bytes_out > in_count) /* exit(2) if no savings */ + exit_stat = 2; +} + +/* + * TAG( output ) + * + * Output the given code. + * Inputs: + * code: A n_bits-bit integer. If == -1, then EOF. This assumes + * that n_bits =< (long)wordsize - 1. + * Outputs: + * Outputs code to the file. + * Assumptions: + * Chars are 8 bits long. + * Algorithm: + * Maintain a BITS character long buffer (so that 8 codes will + * fit in it exactly). When the buffer fills up empty it and start over. + */ + +static char buf[BITS]; + +uchar lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; +uchar rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + +void +output( code ) +code_int code; +{ +#ifdef DEBUG + static int col = 0; +#endif + int r_off = offset, bits= n_bits; + char *bp = buf; + +#ifdef DEBUG + if (verbose) + fprintf(stderr, "%5d%c", code, + (col+=6) >= 74? (col = 0, '\n'): ' '); +#endif + if (code >= 0) { + /* + * byte/bit numbering on the VAX is simulated by the + * following code + */ + /* + * Get to the first byte. + */ + bp += (r_off >> 3); + r_off &= 7; + /* + * Since code is always >= 8 bits, only need to mask the first + * hunk on the left. + */ + *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off]; + bp++; + bits -= 8 - r_off; + code >>= 8 - r_off; + /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ + if ( bits >= 8 ) { + *bp++ = code; + code >>= 8; + bits -= 8; + } + /* Last bits. */ + if(bits) + *bp = code; + + offset += n_bits; + if ( offset == (n_bits << 3) ) { + bp = buf; + bits = n_bits; + bytes_out += bits; + do { + putchar(*bp++); + } while(--bits); + offset = 0; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. + */ + if ( free_ent > maxcode || (clear_flg > 0)) { + /* + * Write the whole buffer, because the input side won't + * discover the size increase until after it has read it. + */ + if ( offset > 0 ) { + if( fwrite( buf, 1, n_bits, stdout ) != n_bits) + writeerr(); + bytes_out += n_bits; + } + offset = 0; + + if ( clear_flg ) { + maxcode = MAXCODE (n_bits = INIT_BITS); + clear_flg = 0; + } else { + n_bits++; + if ( n_bits == maxbits ) + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } +#ifdef DEBUG + if ( debug ) { + fprintf(stderr, + "\nChange to %d bits\n", n_bits); + col = 0; + } +#endif + } + } else { + /* + * At EOF, write the rest of the buffer. + */ + if ( offset > 0 ) + fwrite( buf, 1, (offset + 7) / 8, stdout ); + bytes_out += (offset + 7) / 8; + offset = 0; + fflush( stdout ); +#ifdef DEBUG + if ( verbose ) + fprintf( stderr, "\n" ); +#endif + if( ferror( stdout ) ) + writeerr(); + } +} + +/* + * Decompress stdin to stdout. This routine adapts to the codes in the + * file building the "string" table on-the-fly; requiring no table to + * be stored in the compressed file. The tables used herein are shared + * with those of the compress() routine. See the definitions above. + */ +void +decompress(void) +{ + int finchar; + code_int code, oldcode, incode; + uchar *stackp; + + /* + * As above, initialize the first 256 entries in the table. + */ + maxcode = MAXCODE(n_bits = INIT_BITS); + for (code = 255; code >= 0; code--) { + tab_prefixof(code) = 0; + tab_suffixof(code) = (uchar)code; + } + free_ent = (block_compress? FIRST: 256); + + finchar = oldcode = getcode(); + if(oldcode == -1) /* EOF already? */ + return; /* Get out of here */ + putchar((char)finchar); /* first code must be 8 bits = char */ + if(ferror(stdout)) /* Crash if can't write */ + writeerr(); + stackp = de_stack; + + while ((code = getcode()) > -1) { + if ((code == CLEAR) && block_compress) { + for (code = 255; code >= 0; code--) + tab_prefixof(code) = 0; + clear_flg = 1; + free_ent = FIRST - 1; + if ((code = getcode()) == -1) /* O, untimely death! */ + break; + } + incode = code; + /* + * Special case for KwKwK string. + */ + if (code >= free_ent) { + *stackp++ = finchar; + code = oldcode; + } + + /* + * Generate output characters in reverse order + */ + while (code >= 256) { + *stackp++ = tab_suffixof(code); + code = tab_prefixof(code); + } + *stackp++ = finchar = tab_suffixof(code); + + /* + * And put them out in forward order + */ + do { + putchar(*--stackp); + } while (stackp > de_stack); + + /* + * Generate the new entry. + */ + if ( (code=free_ent) < maxmaxcode ) { + tab_prefixof(code) = (ushort)oldcode; + tab_suffixof(code) = finchar; + free_ent = code+1; + } + /* + * Remember previous code. + */ + oldcode = incode; + } + fflush(stdout); + if(ferror(stdout)) + writeerr(); +} + +/* + * TAG( getcode ) + * + * Read one code from the standard input. If EOF, return -1. + * Inputs: + * stdin + * Outputs: + * code or -1 is returned. + */ +code_int +getcode() +{ + int r_off, bits; + code_int code; + static int offset = 0, size = 0; + static uchar buf[BITS]; + uchar *bp = buf; + + if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) { + /* + * If the next entry will be too big for the current code + * size, then we must increase the size. This implies reading + * a new buffer full, too. + */ + if ( free_ent > maxcode ) { + n_bits++; + if ( n_bits == maxbits ) + maxcode = maxmaxcode; /* won't get any bigger now */ + else + maxcode = MAXCODE(n_bits); + } + if ( clear_flg > 0) { + maxcode = MAXCODE(n_bits = INIT_BITS); + clear_flg = 0; + } + size = fread(buf, 1, n_bits, stdin); + if (size <= 0) + return -1; /* end of file */ + offset = 0; + /* Round size down to integral number of codes */ + size = (size << 3) - (n_bits - 1); + } + r_off = offset; + bits = n_bits; + /* + * Get to the first byte. + */ + bp += (r_off >> 3); + r_off &= 7; + /* Get first part (low order bits) */ + code = (*bp++ >> r_off); + bits -= (8 - r_off); + r_off = 8 - r_off; /* now, offset into code word */ + /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ + if (bits >= 8) { + code |= *bp++ << r_off; + r_off += 8; + bits -= 8; + } + /* high order bits. */ + code |= (*bp & rmask[bits]) << r_off; + offset += n_bits; + return code; +} + +#ifdef DEBUG +printcodes() +{ + /* + * Just print out codes from input file. For debugging. + */ + code_int code; + int col = 0, bits; + + bits = n_bits = INIT_BITS; + maxcode = MAXCODE(n_bits); + free_ent = ((block_compress) ? FIRST : 256 ); + while ( ( code = getcode() ) >= 0 ) { + if ( (code == CLEAR) && block_compress ) { + free_ent = FIRST - 1; + clear_flg = 1; + } + else if ( free_ent < maxmaxcode ) + free_ent++; + if ( bits != n_bits ) { + fprintf(stderr, "\nChange to %d bits\n", n_bits ); + bits = n_bits; + col = 0; + } + fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' ); + } + putc( '\n', stderr ); + exit( 0 ); +} + +code_int sorttab[1<= 0) { + sorttab[codetabof(i)] = i; + } + } + first = block_compress ? FIRST : 256; + for(i = first; i < free_ent; i++) { + fprintf(stderr, "%5d: \"", i); + de_stack[--stack_top] = '\n'; + de_stack[--stack_top] = '"'; + stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff, + stack_top); + for(ent=htabof(sorttab[i]) & ((1< 256; + ent=htabof(sorttab[ent]) & ((1<> maxbits, + stack_top); + } + stack_top = in_stack(ent, stack_top); + fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr); + stack_top = STACK_SIZE; + } + } else if(!debug) { /* decompressing */ + + for ( i = 0; i < free_ent; i++ ) { + ent = i; + c = tab_suffixof(ent); + if ( isascii(c) && isprint(c) ) + fprintf( stderr, "%5d: %5d/'%c' \"", + ent, tab_prefixof(ent), c ); + else + fprintf( stderr, "%5d: %5d/\\%03o \"", + ent, tab_prefixof(ent), c ); + de_stack[--stack_top] = '\n'; + de_stack[--stack_top] = '"'; + for ( ; ent != NULL; + ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) { + stack_top = in_stack(tab_suffixof(ent), stack_top); + } + fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr ); + stack_top = STACK_SIZE; + } + } +} + +int +in_stack(int c, int stack_top) +{ + if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) { + de_stack[--stack_top] = c; + } else { + switch( c ) { + case '\n': de_stack[--stack_top] = 'n'; break; + case '\t': de_stack[--stack_top] = 't'; break; + case '\b': de_stack[--stack_top] = 'b'; break; + case '\f': de_stack[--stack_top] = 'f'; break; + case '\r': de_stack[--stack_top] = 'r'; break; + case '\\': de_stack[--stack_top] = '\\'; break; + default: + de_stack[--stack_top] = '0' + c % 8; + de_stack[--stack_top] = '0' + (c / 8) % 8; + de_stack[--stack_top] = '0' + c / 64; + break; + } + de_stack[--stack_top] = '\\'; + } + return stack_top; +} +#endif /* DEBUG */ + +void +writeerr(void) +{ + perror(ofname); + unlink(ofname); + exit(1); +} + +void +copystat(ifname, ofname) +char *ifname, *ofname; +{ + int mode; + time_t timep[2]; /* should be struct utimbuf */ + struct stat statbuf; + + fclose(stdout); + if (stat(ifname, &statbuf)) { /* Get stat on input file */ + perror(ifname); + return; + } + if (!S_ISREG(statbuf.st_mode)) { + if (quiet) + fprintf(stderr, "%s: ", ifname); + fprintf(stderr, " -- not a regular file: unchanged"); + exit_stat = 1; + } else if (exit_stat == 2 && !force) { + /* No compression: remove file.Z */ + if (!quiet) + fprintf(stderr, " -- file unchanged"); + } else { /* Successful Compression */ + exit_stat = 0; + mode = statbuf.st_mode & 0777; + if (chmod(ofname, mode)) /* Copy modes */ + perror(ofname); + /* Copy ownership */ + chown(ofname, statbuf.st_uid, statbuf.st_gid); + timep[0] = statbuf.st_atime; + timep[1] = statbuf.st_mtime; + /* Update last accessed and modified times */ + utime(ofname, (struct utimbuf *)timep); +// if (unlink(ifname)) /* Remove input file */ +// perror(ifname); + return; /* success */ + } + + /* Unsuccessful return -- one of the tests failed */ + if (unlink(ofname)) + perror(ofname); +} + +/* + * This routine returns 1 if we are running in the foreground and stderr + * is a tty. + */ +int +foreground(void) +{ + if(bgnd_flag) /* background? */ + return 0; + else /* foreground */ + return isatty(2); /* and stderr is a tty */ +} + +void +onintr(int x) +{ + USED(x); + unlink(ofname); + exit(1); +} + +void +oops(int x) /* wild pointer -- assume bad input */ +{ + USED(x); + if (do_decomp == 1) + fprintf(stderr, "uncompress: corrupt input\n"); + unlink(ofname); + exit(1); +} + +void +cl_block(void) /* table clear for block compress */ +{ + long rat; + + checkpoint = in_count + CHECK_GAP; +#ifdef DEBUG + if ( debug ) { + fprintf ( stderr, "count: %ld, ratio: ", in_count ); + prratio ( stderr, in_count, bytes_out ); + fprintf ( stderr, "\n"); + } +#endif /* DEBUG */ + + if (in_count > 0x007fffff) { /* shift will overflow */ + rat = bytes_out >> 8; + if (rat == 0) /* Don't divide by zero */ + rat = 0x7fffffff; + else + rat = in_count / rat; + } else + rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ + if (rat > ratio) + ratio = rat; + else { + ratio = 0; +#ifdef DEBUG + if (verbose) + dump_tab(); /* dump string table */ +#endif + cl_hash((count_int)hsize); + free_ent = FIRST; + clear_flg = 1; + output((code_int)CLEAR); +#ifdef DEBUG + if (debug) + fprintf(stderr, "clear\n"); +#endif /* DEBUG */ + } +} + +void +cl_hash(count_int hsize) /* reset code table */ +{ + count_int *htab_p = htab+hsize; + long i; + long m1 = -1; + + i = hsize - 16; + do { /* might use Sys V memset(3) here */ + *(htab_p-16) = m1; + *(htab_p-15) = m1; + *(htab_p-14) = m1; + *(htab_p-13) = m1; + *(htab_p-12) = m1; + *(htab_p-11) = m1; + *(htab_p-10) = m1; + *(htab_p-9) = m1; + *(htab_p-8) = m1; + *(htab_p-7) = m1; + *(htab_p-6) = m1; + *(htab_p-5) = m1; + *(htab_p-4) = m1; + *(htab_p-3) = m1; + *(htab_p-2) = m1; + *(htab_p-1) = m1; + htab_p -= 16; + } while ((i -= 16) >= 0); + for ( i += 16; i > 0; i-- ) + *--htab_p = m1; +} + +void +prratio(stream, num, den) +FILE *stream; +long num, den; +{ + int q; /* Doesn't need to be long */ + + if(num > 214748L) /* 2147483647/10000 */ + q = num / (den / 10000L); + else + q = 10000L * num / den; /* Long calculations, though */ + if (q < 0) { + putc('-', stream); + q = -q; + } + fprintf(stream, "%d.%02d%%", q / 100, q % 100); +} + +void +version(void) +{ + fprintf(stderr, "%s\n", rcs_ident); + fprintf(stderr, "Options: "); +#ifdef DEBUG + fprintf(stderr, "DEBUG, "); +#endif +#ifdef BSD4_2 + fprintf(stderr, "BSD4_2, "); +#endif + fprintf(stderr, "BITS = %d\n", BITS); +} + +/* + * The revision-history novel: + * + * $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $ + * $Log: compress.c,v $ + * Revision 4.0 85/07/30 12:50:00 joe + * Removed ferror() calls in output routine on every output except first. + * Prepared for release to the world. + * + * Revision 3.6 85/07/04 01:22:21 joe + * Remove much wasted storage by overlaying hash table with the tables + * used by decompress: tab_suffix[1<putc] and + * added signal catcher [plus beef in writeerr()] to delete effluvia. + * + * Revision 2.0 84/08/28 22:00:00 petsd!joe + * Add check for foreground before prompting user. Insert maxbits into + * compressed file. Force file being uncompressed to end with ".Z". + * Added "-c" flag and "zcat". Prepared for release. + * + * Revision 1.10 84/08/24 18:28:00 turtlevax!ken + * Will only compress regular files (no directories), added a magic number + * header (plus an undocumented -n flag to handle old files without headers), + * added -f flag to force overwriting of possibly existing destination file, + * otherwise the user is prompted for a response. Will tack on a .Z to a + * filename if it doesn't have one when decompressing. Will only replace + * file if it was compressed. + * + * Revision 1.9 84/08/16 17:28:00 turtlevax!ken + * Removed scanargs(), getopt(), added .Z extension and unlimited number of + * filenames to compress. Flags may be clustered (-Ddvb12) or separated + * (-D -d -v -b 12), or combination thereof. Modes and other status is + * copied with copystat(). -O bug for 4.2 seems to have disappeared with + * 1.8. + * + * Revision 1.8 84/08/09 23:15:00 joe + * Made it compatible with vax version, installed jim's fixes/enhancements + * + * Revision 1.6 84/08/01 22:08:00 joe + * Sped up algorithm significantly by sorting the compress chain. + * + * Revision 1.5 84/07/13 13:11:00 srd + * Added C version of vax asm routines. Changed structure to arrays to + * save much memory. Do unsigned compares where possible (faster on + * Perkin-Elmer) + * + * Revision 1.4 84/07/05 03:11:11 thomas + * Clean up the code a little and lint it. (Lint complains about all + * the regs used in the asm, but I'm not going to "fix" this.) + * + * Revision 1.3 84/07/05 02:06:54 thomas + * Minor fixes. + * + * Revision 1.2 84/07/05 00:27:27 thomas + * Add variable bit length output. + */ diff --git a/src/cmd/compress/mkfile b/src/cmd/compress/mkfile new file mode 100755 index 00000000..5af1958d --- /dev/null +++ b/src/cmd/compress/mkfile @@ -0,0 +1,15 @@ +<$PLAN9/src/mkhdr + +TARG=\ + compress \ + zcat \ + uncompress + +$O.uncompress:Q: $O.compress + cp $prereq $target + +$O.zcat:Q: $O.compress + cp $prereq $target + +<$PLAN9/src/mkmany + -- cgit v1.2.3 From e75dbb6af8fbea53c62efb7176ed2d25a47557c9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Jan 2020 10:48:20 -0500 Subject: factotum: update for new nbrecvul return value Unclear whether the old semantics were the right ones, but at least this preserves what they've been for the past however many years. --- src/cmd/auth/factotum/confirm.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/auth/factotum/confirm.c b/src/cmd/auth/factotum/confirm.c index 105a46db..8451e8ae 100644 --- a/src/cmd/auth/factotum/confirm.c +++ b/src/cmd/auth/factotum/confirm.c @@ -128,17 +128,33 @@ needkeywrite(char *s) int needkey(Conv *c, Attr *a) { + ulong u; + if(c == nil || *needkeyinuse == 0) return -1; lbappend(&needkeybuf, "needkey tag=%lud %A", c->tag, a); flog("needkey %A", a); - return nbrecvul(c->keywait); + + // Note: This code used to "return nbrecvul(c->keywait)." + // In Jan 2020 we changed nbrecvul to match Plan 9 and + // the man page and return 0 on "no data available" instead + // of -1. This new code with an explicit nbrecv preserves the + // code's old semantics, distinguishing a sent 0 from "no data". + // That said, this code seems to return -1 unconditionally: + // the c->keywait channel is unbuffered, and the only sending + // to it is done with an nbsendul, which won't block waiting for + // a receiver. So there is no sender for nbrecv to find here. + if(nbrecv(c->keywait, &u) < 0) + return -1; + return u; } int badkey(Conv *c, Key *k, char *msg, Attr *a) { + ulong u; + if(c == nil || *needkeyinuse == 0) return -1; @@ -146,5 +162,17 @@ badkey(Conv *c, Key *k, char *msg, Attr *a) c->tag, k->attr, k->privattr, msg, a); flog("badkey %A / %N / %s / %A", k->attr, k->privattr, msg, a); - return nbrecvul(c->keywait); + + // Note: This code used to "return nbrecvul(c->keywait)." + // In Jan 2020 we changed nbrecvul to match Plan 9 and + // the man page and return 0 on "no data available" instead + // of -1. This new code with an explicit nbrecv preserves the + // code's old semantics, distinguishing a sent 0 from "no data". + // That said, this code seems to return -1 unconditionally: + // the c->keywait channel is unbuffered, and the only sending + // to it is done with an nbsendul, which won't block waiting for + // a receiver. So there is no sender for nbrecv to find here. + if(nbrecv(c->keywait, &u) < 0) + return -1; + return u; } -- cgit v1.2.3 From ba60bab3cd247284977ff99573db0c1f3d056953 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Jan 2020 11:09:16 -0500 Subject: devdraw: actually send resize event on resize Fixes #340. Fixes #343. --- src/cmd/devdraw/srv.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c index c98a865f..570091bc 100644 --- a/src/cmd/devdraw/srv.c +++ b/src/cmd/devdraw/srv.c @@ -37,6 +37,8 @@ usage(void) void threadmain(int argc, char **argv) { + char *p; + ARGBEGIN{ case 'D': /* for good ps -a listings */ break; @@ -52,6 +54,10 @@ threadmain(int argc, char **argv) usage(); }ARGEND + fmtinstall('H', encodefmt); + if((p = getenv("DEVDRAWTRACE")) != nil) + trace = atoi(p); + if(srvname == nil) { client0 = mallocz(sizeof(Client), 1); if(client0 == nil){ @@ -417,6 +423,7 @@ gfx_mousetrack(Client *c, int x, int y, int b, uint ms) y = copy->xy.y; b = copy->buttons; ms = copy->msec; + c->mouse.resized = 1; } if(x < c->mouserect.min.x) x = c->mouserect.min.x; -- cgit v1.2.3 From fe2b2de9844749c876df209bb8d9413e0074cbcf Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Jan 2020 11:25:36 -0500 Subject: devdraw: set windowrect correctly on x11 if window gets unexpected size Fixes #54. --- src/cmd/devdraw/x11-screen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c index c3a6fa33..d01e8496 100644 --- a/src/cmd/devdraw/x11-screen.c +++ b/src/cmd/devdraw/x11-screen.c @@ -550,8 +550,6 @@ xattach(Client *client, char *label, char *winsize) havemin = 0; } w = newxwin(client); - w->screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen)); - w->windowrect = r; memset(&attr, 0, sizeof attr); attr.colormap = _x.cmap; @@ -679,6 +677,8 @@ xattach(Client *client, char *label, char *winsize) } }else fprint(2, "XGetWindowAttributes: bad attrs\n"); + w->screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen)); + w->windowrect = r; /* * Allocate our local backing store. -- cgit v1.2.3 From 4241cae2a1ffe7a499ffd9d028e001fea7a678d6 Mon Sep 17 00:00:00 2001 From: Nicola Girardi Date: Sat, 22 Jun 2019 11:44:24 +0100 Subject: cmd/rio: xshove: set geometry by window id --- src/cmd/rio/xshove.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/cmd') diff --git a/src/cmd/rio/xshove.c b/src/cmd/rio/xshove.c index e235874e..7358987e 100644 --- a/src/cmd/rio/xshove.c +++ b/src/cmd/rio/xshove.c @@ -27,6 +27,7 @@ struct Win int y; int dx; int dy; + char *idstr; char *class; char *instance; char *name; @@ -143,6 +144,9 @@ getinfo(void) if(attr.width <= 0 || attr.override_redirect || attr.map_state != IsViewable) continue; ww->xw = xwin[i]; + char idstr[9]; + snprint(idstr, sizeof(idstr), "%08x", (uint)ww->xw); + ww->idstr = strdup(idstr); ww->x = attr.x; ww->y = attr.y; ww->dx = attr.width; @@ -196,7 +200,8 @@ shove(char *name, char *geom) for(i=0; iinstance && strstr(ww->instance, name) - || ww->class && strstr(ww->class, name)){ + || ww->class && strstr(ww->class, name) + || ww->idstr && strstr(ww->idstr, name)){ int value_mask; XWindowChanges e; -- cgit v1.2.3 From 0be57355f912dbedb76cea1a7a4f9a1deb5bde2b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Jan 2020 11:59:45 -0500 Subject: devdraw: avoid deadlock in x11 resize Fixes #347. --- src/cmd/devdraw/x11-inc.h | 1 + src/cmd/devdraw/x11-screen.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/x11-inc.h b/src/cmd/devdraw/x11-inc.h index dca3ebcd..ab4c2505 100644 --- a/src/cmd/devdraw/x11-inc.h +++ b/src/cmd/devdraw/x11-inc.h @@ -17,6 +17,7 @@ #include #include #ifdef SHOWEVENT +#include #include "../rio/showevent/ShowEvent.c" #endif diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c index d01e8496..62f49f2f 100644 --- a/src/cmd/devdraw/x11-screen.c +++ b/src/cmd/devdraw/x11-screen.c @@ -1042,7 +1042,9 @@ _xreplacescreenimage(Client *client) w->nextscreenpm = pixmap; w->screenr = r; client->mouserect = r; + xunlock(); gfx_replacescreenimage(client, m); + xlock(); return 1; } -- cgit v1.2.3 From 7bf2db4c2ae30c0f7b320e57060715bf6279e98a Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Thu, 16 Jan 2020 16:54:19 +0000 Subject: malloc: remove locking The issue manifests in fork: POSIX fork mandates that a fork'd process is created with a single thread. If a multithreaded program forks, and some thread was in malloc() when the fork() happened, then in the child the lock will be held but there will be no thread to release it. We assume the system malloc() must already know how to deal with this and is thread-safe, but it won't know about our custom spinlock. Judging that this is no longer necessary (the lock code was added 15 years ago) we remove it. Signed-off-by: Dan Cross --- src/cmd/9term/malloc.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/9term/malloc.c b/src/cmd/9term/malloc.c index 9132235b..7b590bc4 100644 --- a/src/cmd/9term/malloc.c +++ b/src/cmd/9term/malloc.c @@ -7,8 +7,6 @@ #define NOPLAN9DEFINES #include -static Lock malloclock; - void* p9malloc(ulong n) { @@ -16,9 +14,7 @@ p9malloc(ulong n) if(n == 0) n++; - lock(&malloclock); v = malloc(n); - unlock(&malloclock); print("p9malloc %lud => %p; pc %lux\n", n, v, getcallerpc(&n)); return v; } @@ -28,10 +24,8 @@ p9free(void *v) { if(v == nil) return; - lock(&malloclock); print("p9free %p; pc %lux\n", v, getcallerpc(&v)); free(v); - unlock(&malloclock); } void* @@ -42,9 +36,7 @@ p9calloc(ulong a, ulong b) if(a*b == 0) a = b = 1; - lock(&malloclock); v = calloc(a*b, 1); - unlock(&malloclock); print("p9calloc %lud %lud => %p; pc %lux\n", a, b, v, getcallerpc(&a)); return v; } @@ -54,9 +46,7 @@ p9realloc(void *v, ulong n) { void *vv; - lock(&malloclock); vv = realloc(v, n); - unlock(&malloclock); print("p9realloc %p %lud => %p; pc %lux\n", v, n, vv, getcallerpc(&v)); return vv; } -- cgit v1.2.3 From 1d0d432ccb000b28de3309db5f8299357a46c903 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 16 Jan 2020 12:07:42 -0500 Subject: devdraw: abort alt sequence on window change on macOS Fixes #3. --- src/cmd/devdraw/mac-screen.m | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index 4bc3f088..dedbfb84 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -560,6 +560,10 @@ rpc_resizewindow(Client *c, Rectangle r) [self sendmouse:0]; } +- (void)windowDidResignKey:(id)arg { + gfx_abortcompose(self.client); +} + - (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];} - (void)mouseDown:(NSEvent*)e{ [self getmouse:e];} - (void)mouseDragged:(NSEvent*)e{ [self getmouse:e];} -- cgit v1.2.3 From 93e2e820a5551ba3d0a1e0f0fbd4c5eb65e18ce6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 24 Jan 2020 13:08:36 -0500 Subject: acme: report close failure in Put, this time for sure Missed in 0b349f6f that Bterm is not closing fd. --- src/cmd/acme/exec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c index 1d50f92f..be7936ae 100644 --- a/src/cmd/acme/exec.c +++ b/src/cmd/acme/exec.c @@ -699,7 +699,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) Rune *r; Biobuf *b; char *s, *name; - int i, fd, q, ret; + int i, fd, q, ret, retc; Dir *d, *d1; Window *w; int isapp; @@ -763,9 +763,10 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) goto Rescue2; } ret = Bterm(b); + retc = close(fd); free(b); b = nil; - if(ret < 0) { + if(ret < 0 || retc < 0) { warning(nil, "can't write file %s: %r\n", name); goto Rescue2; // flush or close failed } @@ -785,10 +786,9 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) // in case we don't have read permission. // (The create above worked, so we probably // still have write permission.) - close(fd); fd = open(name, OWRITE); - d1 = dirfstat(fd); + close(fd); if(d1 != nil){ free(d); d = d1; @@ -821,11 +821,11 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname) if(b != nil) { Bterm(b); free(b); + close(fd); } free(h); fbuffree(s); fbuffree(r); - close(fd); /* fall through */ Rescue1: -- cgit v1.2.3 From f66f0a587b48337388296c8f1820f9b3dbfd0085 Mon Sep 17 00:00:00 2001 From: Martin Palma Date: Mon, 3 Feb 2020 20:59:58 +0100 Subject: devdraw: fix `cmd-r` to toggle retina vs. non-retina mode on macOS (#361) and not unexpectedly quitting an application. Fixes #360 --- src/cmd/devdraw/mac-screen.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cmd') diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m index dedbfb84..c6e58341 100644 --- a/src/cmd/devdraw/mac-screen.m +++ b/src/cmd/devdraw/mac-screen.m @@ -510,7 +510,7 @@ void rpc_resizeimg(Client *c) { DrawView *view = (__bridge DrawView*)c->view; - dispatch_sync(dispatch_get_main_queue(), ^(void){ + dispatch_async(dispatch_get_main_queue(), ^(void){ [view resizeimg]; }); } -- cgit v1.2.3