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