💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › d.c captured on 2021-12-17 at 13:26:06.

View Raw

More Information

-=-=-=-=-=-=-

#include <u.h>
#include <libc.h>
#include <bio.h>

/*
	Simple dictionary tool.

	A dictionary consists of two files in $home/lib/dict:

	• dictname:
		flat file with entries separated by lines like:
		⇒headwordkey
	• dictname.idx:
		a sorted file of lines like:
		headword	offset	length

	There is a separate tool to create an index:
	dictidx dictname | sort | uniq > dictname.idx
	
	Usage:	d [dictname] headword

	prints all entries with keys exactly matching headword
	prints nearest match if headword not found
	
	potential additions but too lazy:
	• zipped dictionaries?? or just chmod +t them...
	• line folding
	• context/browsing


Biobuf *index, *dictionary, *output;
char *word;

enum{
	PATHLEN = 128,
	BUFLEN = 8192
};

vlong
getvlong(char delim){
	vlong x;
	char *str;

	str = Brdstr(index, delim, 1);
	if(str == nil)
		sysfatal("getvlong: could not read string");
	x = atoll(str);
	free(str);
	return x;
}

int
checkhw(int *ip, int guess)
{
	char *hw;
	hw = Brdstr(index, '\t', 1);
	if(hw == nil)
		return 0;
	*ip = strcmp(hw, word);
	if(guess && *ip > 0)
		sysfatal("nearest match: %s", hw);
	free(hw);
	return 1;
}

vlong
findfirst(void)
{
	vlong min, mid, max;
	int c;

	min = 0;
	max = Bseek(index, 0, 2);

	for(;;){
		Bseek(index, min + (max - min) / 2, 0);
		Brdline(index, '\n');
		mid = Boffset(index);
		if(mid == max || !checkhw(&c, 0))
			break;
		if(c < 0)
			min = mid;
		else
			max = mid;
	}
	Bseek(index, min, 0);
	for(;;){
		if(!checkhw(&c, 1))
			sysfatal("could not find %s", word);
		if(c == 0)
			break;
		Brdline(index, '\n');
		min = Boffset(index);
	}
	return min;
}

void
main(int argc, char **argv)
{
	char dict[PATHLEN], idx[PATHLEN], buf[BUFLEN];
	int c;
	vlong off, len;
	
	sprint(dict, "%s/lib/dict/oed", getenv("home"));

	ARGBEGIN {
	} ARGEND;
	switch(argc){
	case 2:
		sprint(dict, "%s/lib/dict/%s", getenv("home"), *argv++);
	case 1:
		word = *argv;
		if(*word == '\0')
			sysfatal("empty search key");
		break;
	default:
		sysfatal("Usage: %s [dict] headword\n", argv0);
	}

	sprint(idx, "%s.idx", dict);

	index = Bopen(idx, OREAD);
	if(index == nil) sysfatal("Bopen: %r");
	dictionary = Bopen(dict, OREAD);
	if(dictionary == nil) sysfatal("Bopen: %r");
	output = Bfdopen(1, OWRITE);
	if(output == nil) sysfatal("Bfdopen: %r");

	Bseek(index, findfirst(), 0);
	for(;;){
		if(!checkhw(&c, 0) || c != 0)
			break;
		off = getvlong('\t');
		len = getvlong('\n');
		Bseek(dictionary, off, 0);
		for(; len > BUFLEN; len -= BUFLEN){
			Bread(dictionary, buf, BUFLEN);
			Bwrite(output, buf, BUFLEN);
		}
		Bread(dictionary, buf, len);
		Bwrite(output, buf, len);
		Bputc(output, '\n');
	}
	exits(nil);
}