shithub: neatmkfn

ref: c55c928fc9ce1cdbb8fa8a7aeeb6eea54e2b7657
dir: /mkfn.c/

View raw version
/*
 * NEATMKFN - GENERATE NEATROFF FONT DESCRIPTIONS
 *
 * Copyright (C) 2012-2018 Ali Gholami Rudi <ali at rudi dot ir>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <stdio.h>
#include "mkfn.h"

#define LEN(a)		((sizeof(a) / sizeof((a)[0])))

static char *mkfn_scripts;	/* filtered scripts */
static char *mkfn_langs;	/* filtered languages */
static char *mkfn_subfont;	/* filtered font */
static char *mkfn_trname;	/* font troff name */
static char *mkfn_psname;	/* font ps name */
static char *mkfn_path;		/* font path */
int mkfn_res = 720;		/* device resolution */
int mkfn_warn;			/* warn about unsupported features */
int mkfn_kmin;			/* minimum kerning value */
int mkfn_swid;			/* space width */
int mkfn_special;		/* special flag */
int mkfn_bbox;			/* include bounding box */
int mkfn_noligs;		/* suppress ligatures */
int mkfn_pos = 1;		/* include glyph positions */
int mkfn_dry;			/* generate no output */

/* OpenType specifies a specific feature order for different scripts */
static char *scriptorder[][2] = {
	{"latn", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"cyrl", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"grek", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"armn", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"geor", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"runr", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"ogam", "ccmp,liga,clig,dist,kern,mark,mkmk"},
	{"arab", "ccmp,isol,fina,medi,init,rlig,calt,liga,dlig,cswh,mset,curs,kern,mark,mkmk"},
	{"bugi", "locl,ccmp,rlig,liga,clig,calt,kern,dist,mark,mkmk"},
	{"hang", "ccmp,ljmo,vjmo,tjmo"},
	{"hebr", "ccmp,dlig,kern,mark"},
	{"bng2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"dev2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"gjr2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"gur2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"knd2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"mlym", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"ory2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"tml2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"tml2", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"telu", "locl,nukt,akhn,rphf,blwf,half,pstf,vatu,cjct,init,pres,abvs,blws,psts,haln,calt,kern,dist,abvm,blwm"},
	{"java", "locl,pref,abvf,blwf,pstf,pres,abvs,blws,psts,ccmp,rlig,liga,clig,calt,kern,dist,mark,mkmk"},
	{"khmr", "pref,blwf,abvf,pstf,pres,blws,abvs,psts,clig,dist,blwm,abvm,mkmk"},
	{"lao ", "ccmp,kern,mark,mkmk"},
	{"mym2", "locl,rphf,pref,blwf,pstf,pres,abvs,blws,psts,kern,dist,mark,mkmk"},
	{"sinh", "locl,ccmp,akhn,rphf,vatu,pstf,pres,abvs,blws,psts,kern,dist,abvm,blwm"},
	{"syrc", "stch,ccmp,isol,fina,fin2,fin3,medi,med2,init,rlig,calt,liga,dlig,kern,mark,mkmk"},
	{"thaa", "kern,mark"},
	{"thai", "ccmp,kern,mark,mkmk"},
	{"tibt", "ccmp,abvs,blws,calt,liga,kern,abvm,blwm,mkmk"},
};

/* return 1 if the given script is to be included */
int mkfn_script(char *script, int nscripts)
{
	/* fill mkfn_scripts (if unspecified) in the first call */
	if (!mkfn_scripts) {
		if (nscripts == 1 || !script)
			return 1;
		if (!strcmp("DFLT", script))
			mkfn_scripts = "DFLT";
		else
			mkfn_scripts = "latn";
	}
	if (!strcmp("list", mkfn_scripts))
		printf("%s\n", script ? script : "");
	if (strchr(script, ' '))
		*strchr(script, ' ') = '\0';
	return !!strstr(mkfn_scripts, script);
}

/* return 1 if the given language is to be included */
int mkfn_lang(char *lang, int nlangs)
{
	if (!mkfn_langs)
		return 1;
	if (!lang)
		lang = "";
	if (!strcmp("list", mkfn_langs))
		printf("%s\n", lang);
	if (strchr(lang, ' '))
		*strchr(lang, ' ') = '\0';
	return !!strstr(mkfn_langs, lang);
}

/* return 1 if the given font is to be included */
int mkfn_font(char *font)
{
	static int idx;			/* font index */
	idx++;
	if (!mkfn_subfont)
		return idx == 1;
	if (!strcmp("list", mkfn_subfont))
		printf("%s\n", font);
	if (mkfn_subfont[0] && isdigit((unsigned char) mkfn_subfont[0]))
		if (atoi(mkfn_subfont) == idx)
			return 1;
	return !strcmp(mkfn_subfont, font);
}

/* return the rank of the given feature, for the current script */
int mkfn_featrank(char *scrp, char *feat)
{
	static char **order;
	int i;
	if (!order || strcmp(scrp, order[0])) {
		order = NULL;
		for (i = 0; i < LEN(scriptorder); i++)
			if (!strcmp(scrp, scriptorder[i][0]))
				order = scriptorder[i];
	}
	if (order && strstr(order[1], feat))
		return strstr(order[1], feat) - order[1];
	return 1000;
}

void mkfn_header(char *fontname)
{
	if (mkfn_dry)
		return;
	if (mkfn_trname)
		printf("name %s\n", mkfn_trname);
	if (mkfn_psname)
		printf("fontname %s\n", mkfn_psname);
	if (!mkfn_psname && fontname && fontname[0])
		printf("fontname %s\n", fontname);
	if (mkfn_path)
		printf("fontpath %s\n", mkfn_path);
	trfn_header();
	if (mkfn_special)
		printf("special\n");
	trfn_cdefs();
}

int otf_read(void);
int afm_read(void);

static char *usage =
	"Usage: mktrfn [options] <input >output\n"
	"Options:\n"
	"  -a      \tread an AFM file (default)\n"
	"  -o      \tread a TTF or an OTF file\n"
	"  -s      \tspecial font\n"
	"  -p name \toverride font postscript name\n"
	"  -t name \tset font troff name\n"
	"  -f path \tset font path\n"
	"  -r res  \tset device resolution (720)\n"
	"  -k kmin \tspecify the minimum amount of kerning (0)\n"
	"  -b      \tinclude glyph bounding boxes\n"
	"  -l      \tsuppress the ligatures line\n"
	"  -n      \tsuppress glyph positions\n"
	"  -S scrs \tcomma-separated list of scripts to include (list to list)\n"
	"  -L langs\tcomma-separated list of languages to include (list to list)\n"
	"  -F font \tfont name or index in a font collection (list to list)\n"
	"  -w      \twarn about unsupported font features\n";

int main(int argc, char *argv[])
{
	int afm = 1;
	int i;
	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
		switch (argv[i][1]) {
		case 'a':
			afm = 1;
			break;
		case 'b':
			mkfn_bbox = 1;
			break;
		case 'f':
			mkfn_path = argv[i][2] ? argv[i] + 2 : argv[++i];
			break;
		case 'F':
			mkfn_subfont = argv[i][2] ? argv[i] + 2 : argv[++i];
			mkfn_dry = !strcmp("list", mkfn_subfont);
			break;
		case 'k':
			mkfn_kmin = atoi(argv[i][2] ? argv[i] + 2 : argv[++i]);
			break;
		case 'l':
			mkfn_noligs = 1;
			break;
		case 'L':
			mkfn_langs = argv[i][2] ? argv[i] + 2 : argv[++i];
			mkfn_dry = !strcmp("list", mkfn_langs);
			break;
		case 'n':
			mkfn_pos = 0;
			break;
		case 'o':
			afm = 0;
			break;
		case 'p':
			mkfn_psname = argv[i][2] ? argv[i] + 2 : argv[++i];
			break;
		case 'r':
			mkfn_res = atoi(argv[i][2] ? argv[i] + 2 : argv[++i]);
			break;
		case 's':
			mkfn_special = 1;
			break;
		case 'S':
			mkfn_scripts = argv[i][2] ? argv[i] + 2 : argv[++i];
			mkfn_dry = !strcmp("list", mkfn_scripts);
			break;
		case 't':
			mkfn_trname = argv[i][2] ? argv[i] + 2 : argv[++i];
			break;
		case 'w':
			mkfn_warn = 1;
			break;
		default:
			fprintf(stderr, "%s", usage);
			return 1;
		}
	}
	trfn_init();
	if ((afm ? afm_read() : otf_read())) {
		fprintf(stderr, "neatmkfn: cannot parse the font\n");
		trfn_done();
		return 1;
	}
	trfn_done();
	return 0;
}