Category Archives: Computers

Postscript Template Strings

I’m quite proud of this, even though the program I was writing it for ended up staying a shell script.

% realloc a string
/growstring {  % () -> ()
  dup length 2 mul string dup 0 4 3 roll putinterval
} bind def

% Just a simple template engine.
%
% Anything between curly braces is PS code which returns a
% single object that will be converted to string via cvs.
%
% The embedded code has full access to the environment and
% may invoke the template procedure recursively.
%
% To embed a literal brace, embed a literal string: { ({) }
%
/template {  % (txt { - -> any } txt) -> ()
  10 dict begin /src exch def
    /rv 256 string def
    /rvidx 0 def
    /template-append {
      /o exch def
      { /o load rv rvidx rv length rvidx sub getinterval
        { cvs } stopped
        { /rv rv growstring def }
        { length rvidx add /rvidx exch def exit } ifelse
      } loop
    } //bind def
    {
      % find { or end, appending text
      src ({) search {
        template-append pop
        % search excludes '{', we need it for token
        length 1 add /n exch def
        src dup length n sub n getinterval /src exch def
      } { template-append exit } ifelse

      % (src) is now ({code}...)
      % eval the code and append any resulting objects
      src token {
        exch /src exch def
        % a closure to restore our hidden local scope
        [ exch /exec cvx currentdict /begin cvx ] cvx
        end exec template-append
      } if
    } loop
    rv 0 rvidx getinterval
  end
} bind def

% tests
/bar (ggg) def
(foo) template ==
(foo{bar} foo) template ==
({bar}foo) template ==
(foo{bar}) template ==
(foo{({)}{bar}) template ==
/rvidx (uuu) def
(foo{rvidx}foo) template ==
55 44 33 (foo{1 index}foo) template == pop pop pop
(sss{ ({rvidx}) template }www) template ==

Postscript Underline

  • Supports all show operators, including custom procedures.
  • Can draw a single underline rect across multiple show operations (and will be correct, if the currentfont remains the same).
  • Supports any and all font matrix munging.
  • Supports underlines of a different color from the text.
  • The second calling variant draws underlines underneath the text.
  • Uses font’s underline definitions if available, commonly used defaults (i.e., the values found in most fonts) if not.

Exercise for the reader: have it simply draw the rect and leave it in the currentpath for the caller to have fun with: clip, stroke, whatever.

TODO: Vertical fonts. Do thy have underlines? (I guess it would be “sidelines.”)

%!
% Public Domain 2014 by the other anonymous
%
% startX startY underline -
% {show} underline -
%
% (startX,startY) is the point where the text was started. The underline
% will follow the text to the currentpoint.
%
% The {show} variant draws the underline underneath the text. This allows
% the underline to be a different color than the text (the underline color
% will be the current color and {show} may change the text color).
% To draw the underline underneath the text, we have to exec the {show}
% procedure twice. We clip it into nothing so that it is only drawn once.
%
% NOTE: Since we exec {show} multiple times, it is NOT allowed to modify
% anything besides the graphics state.
/$underline 10 dict def
/underline {
  $underline begin
    dup xcheck {
      gsave
        currentpoint /y0 exch def /x0 exch def
        0 0 0 0 rectclip x0 y0 moveto
        end dup exec $underline begin
        currentpoint /y1 exch def /x1 exch def
      grestore
    } {
      /y0 exch def /x0 exch def
      currentpoint /y1 exch def /x1 exch def
      [ x1 y1 /moveto cvx ] cvx
    } ifelse

    /mtx currentfont /FontMatrix get def
    /info currentfont /FontInfo get def
    0 info /UnderlineThickness 2 copy known { get } { pop pop 50 } ifelse
    0 info /UnderlinePosition 2 copy known { get } { pop pop -100 } ifelse
      mtx transform /uy exch def /ux exch def
      mtx dtransform /uh exch def /uw exch def

    x0 ux add        y0 uy add        moveto
    x0 ux add uw sub y0 uy add uh sub lineto
    x1 ux add uw sub y1 uy add uh sub lineto
    x1 ux add        y1 uy add        lineto
    closepath fill
    x0 y0 moveto
  end exec
} bind def

% Test:
/Times-Roman 100 selectfont
50 300 moveto { (abcdefghi) show } underline
1 0 1 setrgbcolor
50 200 moveto { 0 setgray 1 1 (jklmnopqr) ashow } underline
/Times-Roman [ 100 5 5 100 -40 -30 ] selectfont
50 100 moveto { (sjtuvwxyz) show } underline
showpage

Floating Point Approximate Equality

I posted an earlier version of this on Tumblr. It had bugs (namely, it ignored signedness). Here’s an improved version.

#include <math.h>

/* Test (min / max) for closeness to 1 (i.e., what fraction of
 * 'max' is 'min'?). And since (min / max >= cutoff) is equivalent
 * to (min >= cutoff * max), we can avoid division. (I'm reminded
 * of a young linear interpolation...)
 *
 * The best way to craft the cutoff constant is to subtract epsilon
 * from 1.0, with epsilon defined in terms of the smallest value
 * with exponent 0 (i.e., the ULP of 1.0). Here, we fake it.
 *
 * NOTE: .99999... approaches 1. Thou shall not Proliferate thy Nines
 * lest thou incur the Confusion of the Internal strtod() of the Dread
 * Compiler (Blessed be Her Grammar).
 *
 * NOTE: The approximation threshold scales. As the values approach
 * zero, so does the threshold. In other words, a positive can never
 * approximately equal a negative.
 *
 * NOTE: This has not been thoroughly tested. Approximate function
 * is approximate.
 */
int
approx(double a, double b)
{
#define CUTOFF .9999999 /* 15-17 significant digits; stop halfway */
  double da = fabs(a);
  double db = fabs(b);
  int samesigns = (da == a) == (db == b); /* both pos or neg */
  if (da > db) { double tmp = da; da = db; db = tmp; }
  return samesigns && da >= (db * CUTOFF);
}

#ifdef TEST
#include <stdio.h>

void
test_approx(void)
{
  struct {
    int rv;
    double a;
    double b;
  } tests[] = {
    { 0, 1, 1.1 },
    { 1, 1, 1.00000005 },
    { 0, -1, 1.00000005 },
    { 0, 1, -1.00000005 },
    { 1, -1, -1.00000005 },
    { 0, .000000001, .000000005 },
    { 0, -.000000001, .000000005 },
    { 0, .000000001, -.000000005 },
    { 0, -.000000001, -.000000005 },
    { 0, 1, 2 },
    { 0, 0.5, 0.6 },
    { 0, 0.000005, 0.000006 },
    { 0, 1e100, 2e100 },
    { 1, .9999999999e0, 1e0 },
    { 1, .9999999999e1, 1e1 },
    { 1, .9999999999e10, 1e10 },
    { 1, .9999999999e20, 1e20 },
    { 1, .9999999999e30, 1e30 },
    { 1, .9999999999e31, 1e31 },
    { 1, .9999999999e32, 1e32 },
    { 1, .9999999999e33, 1e33 },
    { 1, .9999999999e50, 1e50 },
    { 1, .9999999999e62, 1e62 },
    { 1, .9999999999e63, 1e63 },
    { 1, .9999999999e64, 1e64 },
    { 1, .9999999999e65, 1e65 },
    { 1, .9999999999e100, 1e100 },
    { 1, .9999999999e200, 1e200 },
    { 1, .9999999999e300, 1e300 },
    { 1, .9999999999e-1, 1e-1 },
    { 1, .9999999999e-2, 1e-2 },
    { 1, .9999999999e-10, 1e-10 },
    { 1, .9999999999e-20, 1e-20 },
    { 1, .9999999999e-30, 1e-30 },
    { 1, .9999999999e-40, 1e-40 },
    { 1, .9999999999e-100, 1e-100 },
    { 1, .9999999999e-200, 1e-200 },
    { 1, .9999999999e-300, 1e-300 },
    { 0, 2e0, 1e0 },
    { 0, 2e1, 1e1 },
    { 0, 2e10, 1e10 },
    { 0, 2e20, 1e20 },
    { 0, 2e30, 1e30 },
    { 0, 2e31, 1e31 },
    { 0, 2e32, 1e32 },
    { 0, 2e33, 1e33 },
    { 0, 2e50, 1e50 },
    { 0, 2e62, 1e62 },
    { 0, 2e63, 1e63 },
    { 0, 2e64, 1e64 },
    { 0, 2e65, 1e65 },
    { 0, 2e100, 1e100 },
    { 0, 2e200, 1e200 },
    { 0, 2e300, 1e300 },
    { 0, 2e-1, 1e-1 },
    { 0, 2e-2, 1e-2 },
    { 0, 2e-10, 1e-10 },
    { 0, 2e-20, 1e-20 },
    { 0, 2e-30, 1e-30 },
    { 0, 2e-40, 1e-40 },
    { 0, 2e-100, 1e-100 },
    { 0, 2e-200, 1e-200 },
    { 0, 2e-300, 1e-300 },
    { -1, 0.0, 0.0 }
  };
  size_t i;
  int rv;
  for (i = 0; tests[i].rv >= 0; ++i) {
    if (tests[i].a == tests[i].b)
      printf("approx failed: malformed test %d: %15.15g == %15.15g\n",
             (int)i, tests[i].a, tests[i].b);
    rv = approx(tests[i].a, tests[i].b);
    if (rv != tests[i].rv)
      printf("approx failed: %15.15g %15.15g -> %d should be %d (test %d) # %15.15g %15.15g\n",
             tests[i].a, tests[i].b, rv, tests[i].rv, (int)i,
             tests[i].a * CUTOFF, tests[i].b * CUTOFF);
  }
}

int
main(void)
{
  test_approx();
  printf("math done\n");
  return 0;
}

#endif

Display a random wallpaper on WinXP

Two files, ImageMagick, and a scheduled task.

Copy the following into files:

random.vbs:

'Run random.bat without displaying a window
CreateObject("Wscript.Shell").Run "random.bat", 0, True

random.bat:

@echo off
set img=
set len=0
for /f "delims=" %%a IN ('dir /b /s *.png') do (
set /a len+=1
)
if %len%==0 goto :END
set /a idx=%random% %% %len%
for /f "skip=%idx% delims=" %%a IN ('dir /b /s *.png') do (
set img=%%a
goto :BRK
)
:BRK
IMconvert "%img%" bmp3:random.bmp
RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters 
:END
exit

Note: As you can see above, I renamed convert to IMconvert because of a well-known naming conflict.

  1. Place those two files in, I don’t know, maybe MyDocs/MyPics/Wallpapers or where ever.
  2. Add all kinds of PNG images to the folder from step one. Sub-folders are welcome.
  3. Run random.bat or random.vbs once to produce random.bmp.
  4. Set your wallpaper to random.bmp.
  5. In the Control Panel, you’ll find Scheduled Tasks. Make a new one and set it to random.vbs. Play around with the options for the task. I have mine set for logon, system idle, and at fixed times throughout the day.

That’s it. Enjoy!

Jailbreak the Patriarchy for GreaseMonkey

Jailbreak the Patriarchy for GreaseMonkey.

I feel productive.