On 16/03/10 09:58 AM, Pat Suwalski wrote:
I wrote a very similar patch, but I based the name of the
cached/precompiled file on a sha1 hash of source file.

Actually, I had forgotten that in the most recent revision of my method, I got tired of patching the X server.

Instead, I wrote the attached wrapper to xkbcomp (with a packaging diversion of the actual xkbcomp to xkbcomp.real). That way, I didn't have to patch anything.

Ideally, this methodology would be in the real xkbcomp, and then the rather ugly parameter parsing could be avoided. I'm sure it's error prone; this program is only meant to react to the "-xkm" switch and pass everything else along.

In my testing, this was enough to get just about all of the performance advantage of the patch to the X server itself. Timing tests didn't show any difference, in fact.

--Pat
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <gcrypt.h>

#define CACHEPATH "/var/cache/xkb"

int main(int argc, char *argv[])
{
  int i, intercept = 0;
  char buf[4096];
  unsigned char shasum[20];
  char filename[256];
  char fullfilename[256];
  char *infile = NULL;
  char *outfile = NULL;
  int filesize = 0;
  size_t len;

  /* Simple parameter checking that at least passes the X.org server uses. */
  for (i=1; i<argc; i++)
  {
    /* Sometimes output is with "-o". */
    if (strcmp(argv[i], "-o") == 0 && (i+1 < argc))
    {
      i++;
      outfile = argv[i];
      continue;
    }

    /* Only intercept -xkm. */
    if (strcmp(argv[i], "-xkm") == 0)
    {
      intercept = 1;
      continue;
    }

    if (argv[i][0] != '-' || strcmp(argv[i], "-") == 0)
    {
      if (infile == NULL) infile = argv[i];
      else if (outfile == NULL) outfile = argv[i];
      continue;
    }

    /* Skip over parameters that are supposed to have parameters. */
    if (argv[i][0] == '-')
    {
      switch(argv[i][1])
      {
        case 'e':
        case 'I':
        case 'i':
        case 'm':
        case 'o':
        case 'w':
           i++; break;;
        default:
           break;;
      }

      continue;
    }
  }

  /* If we're producing xkm but not from stdin, don't intercept. If there is
     no outfile, don't intercept. */
  if (intercept && (strcmp(infile, "-") != 0 || outfile == NULL))
    intercept = 0;

  if (strcmp(infile, "-") == 0)
  {
    while (1) {
      /* Read 256 bytes at a time and append to the sha1 sum. */
      len = read(STDIN_FILENO, &buf, 1024);

      if (len == 0) break;

      filesize += len;
    }
  }

  if (intercept)
  {
    /* Take the sha1 sum of the file contents. */
    gcry_md_hd_t h;
    gcry_md_open(&h, GCRY_MD_SHA1, 0);
    gcry_md_write(h, &buf, filesize);
    memcpy(shasum, gcry_md_read(h, GCRY_MD_SHA1), 20);
    gcry_md_close(h);

    /* Convert the sha1 sum to a hex filename. */
    for(i=0; i<20; i++)
    {
      sprintf(&(filename[i*2]), "%02x", shasum[i]);
    }

    sprintf(fullfilename, "%s/%s", CACHEPATH, filename);

    /* If there is a cached copy, symlink it. */
    struct stat ff;
    if (stat(fullfilename, &ff) == 0 && ff.st_mode & S_IFREG) {
      symlink(fullfilename, outfile);
      return 0;
    }
  }

  /* If we got here, we have to run the real xkbcomp. */
  char command[512];
  strcat(command, "/usr/bin/xkbcomp.real");

  /* Format the arguments. */
  for (i=1; i<argc; i++)
  {
    strcat(command, " \"");
    strcat(command, argv[i]);
    strcat(command, "\"");
  }

  /* Pipe out to the real program. */
  FILE *out = popen(command, "w");
  fwrite(&buf, filesize, 1, out);
  i = pclose(out);

  /* Keep a copy in the cache for next time. */
  if (intercept)
  {
    struct stat d;
    stat(CACHEPATH, &d);
    if (!(d.st_mode & S_IFDIR)) mkdir(CACHEPATH, 0755);
    sprintf(command, "cp \"%s\" \"%s\"", outfile, fullfilename);
    system(command);
  }

  return i;
}
_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to