780 lines
18 KiB
C++
780 lines
18 KiB
C++
// -*- C++ -*-
|
|
/* Copyright (C) 1994 Free Software Foundation, Inc.
|
|
Written by James Clark (jjc@jclark.com)
|
|
|
|
This file is part of groff.
|
|
|
|
groff is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2, or (at your option) any later
|
|
version.
|
|
|
|
groff is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with groff; see the file COPYING. If not, write to the Free Software
|
|
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
/*
|
|
TODO
|
|
put human readable font name in device file
|
|
devise new names for useful characters
|
|
use --- for unnamed characters
|
|
option to specify symbol sets to look in
|
|
make it work with TrueType fonts
|
|
put filename in error messages (or fix lib)
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "assert.h"
|
|
#include "lib.h"
|
|
#include "posix.h"
|
|
#include "errarg.h"
|
|
#include "error.h"
|
|
#include "cset.h"
|
|
|
|
#define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
|
|
|
|
const int MULTIPLIER = 3;
|
|
|
|
inline
|
|
int scale(int n)
|
|
{
|
|
return n * MULTIPLIER;
|
|
}
|
|
|
|
// tags in TFM file
|
|
|
|
enum tag_type {
|
|
min_tag = 400,
|
|
type_tag = 400,
|
|
symbol_set_tag = 404,
|
|
msl_tag = 403,
|
|
inches_per_point_tag = 406,
|
|
design_units_per_em_tag = 408,
|
|
posture_tag = 409,
|
|
stroke_weight_tag = 411,
|
|
spacing_tag = 412,
|
|
slant_tag = 413,
|
|
appearance_width_tag = 414,
|
|
word_spacing_tag = 421,
|
|
x_height_tag = 424,
|
|
lower_ascent_tag = 427,
|
|
lower_descent_tag = 428,
|
|
width_tag = 433,
|
|
left_extent_tag = 435,
|
|
right_extent_tag = 436,
|
|
ascent_tag = 437,
|
|
descent_tag = 438,
|
|
pair_kern_tag = 439,
|
|
typeface_tag = 442,
|
|
max_tag = 443
|
|
};
|
|
|
|
// types in TFM file
|
|
|
|
enum {
|
|
ENUM_TYPE = 1,
|
|
BYTE_TYPE = 2,
|
|
USHORT_TYPE = 3,
|
|
FLOAT_TYPE = 5,
|
|
SIGNED_SHORT_TYPE = 17
|
|
};
|
|
|
|
|
|
typedef unsigned char byte;
|
|
typedef unsigned short uint16;
|
|
typedef short int16;
|
|
typedef unsigned int uint32;
|
|
|
|
class File {
|
|
public:
|
|
File(const char *);
|
|
void skip(int n);
|
|
byte get_byte();
|
|
uint16 get_uint16();
|
|
uint32 get_uint32();
|
|
void seek(uint32 n);
|
|
private:
|
|
unsigned char *buf_;
|
|
const unsigned char *ptr_;
|
|
const unsigned char *end_;
|
|
};
|
|
|
|
struct entry {
|
|
char present;
|
|
uint16 type;
|
|
uint32 count;
|
|
uint32 value;
|
|
entry() : present(0) { }
|
|
};
|
|
|
|
struct char_info {
|
|
uint16 msl;
|
|
uint16 width;
|
|
uint16 ascent;
|
|
int16 descent;
|
|
int16 left_extent;
|
|
uint16 right_extent;
|
|
uint16 symbol_set;
|
|
unsigned char code;
|
|
};
|
|
|
|
const uint16 NO_SYMBOL_SET = 0;
|
|
|
|
struct name_list {
|
|
char *name;
|
|
name_list *next;
|
|
name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { }
|
|
~name_list() { a_delete name; }
|
|
};
|
|
|
|
struct symbol_set {
|
|
uint16 select;
|
|
uint16 index[256];
|
|
};
|
|
|
|
#define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64))
|
|
|
|
uint16 text_symbol_sets[] = {
|
|
SYMBOL_SET(0, 'N'), // Latin 1
|
|
SYMBOL_SET(6, 'J'), // Microsoft Publishing
|
|
SYMBOL_SET(2, 'N'), // Latin 2
|
|
0
|
|
};
|
|
|
|
uint16 special_symbol_sets[] = {
|
|
SYMBOL_SET(8, 'M'),
|
|
SYMBOL_SET(5, 'M'),
|
|
SYMBOL_SET(15, 'U'),
|
|
0
|
|
};
|
|
|
|
entry tags[max_tag + 1 - min_tag];
|
|
|
|
char_info *char_table;
|
|
uint32 nchars;
|
|
|
|
int msl_name_table_size = 0;
|
|
name_list **msl_name_table = 0;
|
|
|
|
int n_symbol_sets;
|
|
symbol_set *symbol_set_table;
|
|
|
|
static int special_flag = 0;
|
|
static int italic_flag = 0;
|
|
static int italic_sep;
|
|
|
|
static void usage();
|
|
static const char *xbasename(const char *);
|
|
static void read_tags(File &);
|
|
static void check_type();
|
|
static void check_units(File &);
|
|
static int read_map(const char *);
|
|
static void require_tag(tag_type);
|
|
static void dump_tags(File &f);
|
|
static void output_spacewidth();
|
|
static void output_pclweight();
|
|
static void output_pclproportional();
|
|
static void read_and_output_pcltypeface(File &);
|
|
static void output_pclstyle();
|
|
static void output_slant();
|
|
static void output_ligatures();
|
|
static void read_symbol_sets(File &);
|
|
static void read_and_output_kernpairs(File &);
|
|
static void output_charset();
|
|
static void read_char_table(File &f);
|
|
|
|
inline
|
|
entry &tag_info(tag_type t)
|
|
{
|
|
return tags[t - min_tag];
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
program_name = argv[0];
|
|
|
|
int opt;
|
|
int debug_flag = 0;
|
|
|
|
while ((opt = getopt(argc, argv, "dsvi:")) != EOF) {
|
|
switch (opt) {
|
|
case 'd':
|
|
debug_flag = 1;
|
|
break;
|
|
case 's':
|
|
special_flag = 1;
|
|
break;
|
|
case 'i':
|
|
italic_flag = 1;
|
|
italic_sep = atoi(optarg);
|
|
break;
|
|
case 'v':
|
|
{
|
|
extern const char *version_string;
|
|
fprintf(stderr, "hpftodit version %s\n", version_string);
|
|
fflush(stderr);
|
|
break;
|
|
}
|
|
break;
|
|
case '?':
|
|
usage();
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
if (argc - optind != 3)
|
|
usage();
|
|
File f(argv[optind]);
|
|
if (!read_map(argv[optind + 1]))
|
|
exit(1);
|
|
current_filename = 0;
|
|
current_lineno = -1; // no line numbers
|
|
if (freopen(argv[optind + 2], "w", stdout) == 0)
|
|
fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno));
|
|
current_filename = argv[optind];
|
|
printf("name %s\n", xbasename(argv[optind + 2]));
|
|
if (special_flag)
|
|
printf("special\n");
|
|
read_tags(f);
|
|
check_type();
|
|
check_units(f);
|
|
if (debug_flag)
|
|
dump_tags(f);
|
|
read_char_table(f);
|
|
output_spacewidth();
|
|
output_slant();
|
|
read_and_output_pcltypeface(f);
|
|
output_pclproportional();
|
|
output_pclweight();
|
|
output_pclstyle();
|
|
read_symbol_sets(f);
|
|
output_ligatures();
|
|
read_and_output_kernpairs(f);
|
|
output_charset();
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "usage: %s [-s] [-i n] tfm_file map_file output_font\n",
|
|
program_name);
|
|
exit(1);
|
|
}
|
|
|
|
File::File(const char *s)
|
|
{
|
|
int fd = open(s, O_RDONLY);
|
|
if (fd < 0)
|
|
fatal("cannot open `%1': %2", s, strerror(errno));
|
|
current_filename = s;
|
|
struct stat sb;
|
|
if (fstat(fd, &sb) < 0)
|
|
fatal("cannot stat: %1", strerror(errno));
|
|
if (!S_ISREG(sb.st_mode))
|
|
fatal("not a regular file");
|
|
buf_ = new unsigned char[sb.st_size];
|
|
long nread = read(fd, buf_, sb.st_size);
|
|
if (nread < 0)
|
|
fatal("read error: %1", strerror(errno));
|
|
if (nread != sb.st_size)
|
|
fatal("read unexpected number of bytes");
|
|
ptr_ = buf_;
|
|
end_ = buf_ + sb.st_size;
|
|
}
|
|
|
|
void File::skip(int n)
|
|
{
|
|
if (end_ - ptr_ < n)
|
|
fatal("unexpected end of file");
|
|
ptr_ += n;
|
|
}
|
|
|
|
void File::seek(uint32 n)
|
|
{
|
|
if (end_ - buf_ < n)
|
|
fatal("unexpected end of file");
|
|
ptr_ = buf_ + n;
|
|
}
|
|
|
|
byte File::get_byte()
|
|
{
|
|
if (ptr_ >= end_)
|
|
fatal("unexpected end of file");
|
|
return *ptr_++;
|
|
}
|
|
|
|
uint16 File::get_uint16()
|
|
{
|
|
if (end_ - ptr_ < 2)
|
|
fatal("unexpected end of file");
|
|
uint16 n = *ptr_++;
|
|
return n + (*ptr_++ << 8);
|
|
}
|
|
|
|
uint32 File::get_uint32()
|
|
{
|
|
if (end_ - ptr_ < 4)
|
|
fatal("unexpected end of file");
|
|
uint32 n = *ptr_++;
|
|
for (int i = 0; i < 3; i++)
|
|
n += *ptr_++ << (i + 1)*8;
|
|
return n;
|
|
}
|
|
|
|
static
|
|
void read_tags(File &f)
|
|
{
|
|
if (f.get_byte() != 'I' || f.get_byte() != 'I')
|
|
fatal("not an Intel format TFM file");
|
|
f.skip(6);
|
|
uint16 ntags = f.get_uint16();
|
|
entry dummy;
|
|
for (uint16 i = 0; i < ntags; i++) {
|
|
uint16 tag = f.get_uint16();
|
|
entry *p;
|
|
if (min_tag <= tag && tag <= max_tag)
|
|
p = tags + (tag - min_tag);
|
|
else
|
|
p = &dummy;
|
|
p->present = 1;
|
|
p->type = f.get_uint16();
|
|
p->count = f.get_uint32();
|
|
p->value = f.get_uint32();
|
|
}
|
|
}
|
|
|
|
static
|
|
void check_type()
|
|
{
|
|
require_tag(type_tag);
|
|
if (tag_info(type_tag).value != 0) {
|
|
if (tag_info(type_tag).value == 2)
|
|
fatal("cannot handle TrueType tfm files");
|
|
fatal("unknown type tag %1", int(tag_info(type_tag).value));
|
|
}
|
|
}
|
|
|
|
static
|
|
void check_units(File &f)
|
|
{
|
|
require_tag(design_units_per_em_tag);
|
|
f.seek(tag_info(design_units_per_em_tag).value);
|
|
uint32 num = f.get_uint32();
|
|
uint32 den = f.get_uint32();
|
|
if (num != 8782 || den != 1)
|
|
fatal("design units per em != 8782/1");
|
|
require_tag(inches_per_point_tag);
|
|
f.seek(tag_info(inches_per_point_tag).value);
|
|
num = f.get_uint32();
|
|
den = f.get_uint32();
|
|
if (num != 100 || den != 7231)
|
|
fatal("inches per point not 100/7231");
|
|
}
|
|
|
|
static
|
|
void require_tag(tag_type t)
|
|
{
|
|
if (!tag_info(t).present)
|
|
fatal("tag %1 missing", int(t));
|
|
}
|
|
|
|
static
|
|
void output_spacewidth()
|
|
{
|
|
require_tag(word_spacing_tag);
|
|
printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value));
|
|
}
|
|
|
|
static
|
|
void read_symbol_sets(File &f)
|
|
{
|
|
uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count;
|
|
n_symbol_sets = symbol_set_dir_length/14;
|
|
symbol_set_table = new symbol_set[n_symbol_sets];
|
|
int i;
|
|
for (i = 0; i < n_symbol_sets; i++) {
|
|
f.seek(tag_info(symbol_set_tag).value + i*14);
|
|
(void)f.get_uint32();
|
|
uint32 off1 = f.get_uint32();
|
|
uint32 off2 = f.get_uint32();
|
|
(void)f.get_uint16(); // what's this for?
|
|
f.seek(off1);
|
|
int j;
|
|
uint16 kind = 0;
|
|
for (j = 0; j < off2 - off1; j++) {
|
|
unsigned char c = f.get_byte();
|
|
if ('0' <= c && c <= '9')
|
|
kind = kind*10 + (c - '0');
|
|
else if ('A' <= c && c <= 'Z')
|
|
kind = kind*32 + (c - 64);
|
|
}
|
|
symbol_set_table[i].select = kind;
|
|
for (j = 0; j < 256; j++)
|
|
symbol_set_table[i].index[j] = f.get_uint16();
|
|
}
|
|
for (i = 0; i < nchars; i++)
|
|
char_table[i].symbol_set = NO_SYMBOL_SET;
|
|
|
|
uint16 *symbol_set_selectors = (special_flag
|
|
? special_symbol_sets
|
|
: text_symbol_sets);
|
|
for (i = 0; symbol_set_selectors[i] != 0; i++) {
|
|
int j;
|
|
for (j = 0; j < n_symbol_sets; j++)
|
|
if (symbol_set_table[j].select == symbol_set_selectors[i])
|
|
break;
|
|
if (j < n_symbol_sets) {
|
|
for (int k = 0; k < 256; k++) {
|
|
uint16 index = symbol_set_table[j].index[k];
|
|
if (index != 0xffff
|
|
&& char_table[index].symbol_set == NO_SYMBOL_SET) {
|
|
char_table[index].symbol_set = symbol_set_table[j].select;
|
|
char_table[index].code = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
void read_char_table(File &f)
|
|
{
|
|
require_tag(msl_tag);
|
|
nchars = tag_info(msl_tag).count;
|
|
char_table = new char_info[nchars];
|
|
|
|
f.seek(tag_info(msl_tag).value);
|
|
uint32 i;
|
|
for (i = 0; i < nchars; i++)
|
|
char_table[i].msl = f.get_uint16();
|
|
|
|
require_tag(width_tag);
|
|
f.seek(tag_info(width_tag).value);
|
|
for (i = 0; i < nchars; i++)
|
|
char_table[i].width = f.get_uint16();
|
|
|
|
require_tag(ascent_tag);
|
|
f.seek(tag_info(ascent_tag).value);
|
|
for (i = 0; i < nchars; i++) {
|
|
char_table[i].ascent = f.get_uint16();
|
|
}
|
|
|
|
require_tag(descent_tag);
|
|
f.seek(tag_info(descent_tag).value);
|
|
for (i = 0; i < nchars; i++) {
|
|
char_table[i].descent = f.get_uint16();
|
|
if (char_table[i].descent > 0)
|
|
char_table[i].descent = 0;
|
|
}
|
|
|
|
require_tag(left_extent_tag);
|
|
f.seek(tag_info(left_extent_tag).value);
|
|
for (i = 0; i < nchars; i++)
|
|
char_table[i].left_extent = int16(f.get_uint16());
|
|
|
|
require_tag(right_extent_tag);
|
|
f.seek(tag_info(right_extent_tag).value);
|
|
for (i = 0; i < nchars; i++)
|
|
char_table[i].right_extent = f.get_uint16();
|
|
}
|
|
|
|
static
|
|
void output_pclweight()
|
|
{
|
|
require_tag(stroke_weight_tag);
|
|
int stroke_weight = tag_info(stroke_weight_tag).value;
|
|
int pcl_stroke_weight;
|
|
if (stroke_weight < 128)
|
|
pcl_stroke_weight = -3;
|
|
else if (stroke_weight == 128)
|
|
pcl_stroke_weight = 0;
|
|
else if (stroke_weight <= 145)
|
|
pcl_stroke_weight = 1;
|
|
else if (stroke_weight <= 179)
|
|
pcl_stroke_weight = 3;
|
|
else
|
|
pcl_stroke_weight = 4;
|
|
printf("pclweight %d\n", pcl_stroke_weight);
|
|
}
|
|
|
|
static
|
|
void output_pclproportional()
|
|
{
|
|
require_tag(spacing_tag);
|
|
printf("pclproportional %d\n", tag_info(spacing_tag).value == 0);
|
|
}
|
|
|
|
static
|
|
void read_and_output_pcltypeface(File &f)
|
|
{
|
|
printf("pcltypeface ");
|
|
require_tag(typeface_tag);
|
|
f.seek(tag_info(typeface_tag).value);
|
|
for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) {
|
|
unsigned char c = f.get_byte();
|
|
if (c == '\0')
|
|
break;
|
|
putchar(c);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static
|
|
void output_pclstyle()
|
|
{
|
|
unsigned pcl_style = 0;
|
|
// older tfms don't have the posture tag
|
|
if (tag_info(posture_tag).present) {
|
|
if (tag_info(posture_tag).value)
|
|
pcl_style |= 1;
|
|
}
|
|
else {
|
|
require_tag(slant_tag);
|
|
if (tag_info(slant_tag).value != 0)
|
|
pcl_style |= 1;
|
|
}
|
|
require_tag(appearance_width_tag);
|
|
if (tag_info(appearance_width_tag).value < 100) // guess
|
|
pcl_style |= 4;
|
|
printf("pclstyle %d\n", pcl_style);
|
|
}
|
|
|
|
static
|
|
void output_slant()
|
|
{
|
|
require_tag(slant_tag);
|
|
int slant = int16(tag_info(slant_tag).value);
|
|
if (slant != 0)
|
|
printf("slant %f\n", slant/100.0);
|
|
}
|
|
|
|
static
|
|
void output_ligatures()
|
|
{
|
|
// don't use ligatures for fixed space font
|
|
require_tag(spacing_tag);
|
|
if (tag_info(spacing_tag).value != 0)
|
|
return;
|
|
static const char *ligature_names[] = {
|
|
"fi", "fl", "ff", "ffi", "ffl"
|
|
};
|
|
|
|
static const char *ligature_chars[] = {
|
|
"fi", "fl", "ff", "Fi", "Fl"
|
|
};
|
|
|
|
unsigned ligature_mask = 0;
|
|
int i;
|
|
for (i = 0; i < nchars; i++) {
|
|
uint16 msl = char_table[i].msl;
|
|
if (msl < msl_name_table_size
|
|
&& char_table[i].symbol_set != NO_SYMBOL_SET) {
|
|
for (name_list *p = msl_name_table[msl]; p; p = p->next)
|
|
for (int j = 0; j < SIZEOF(ligature_chars); j++)
|
|
if (strcmp(p->name, ligature_chars[j]) == 0) {
|
|
ligature_mask |= 1 << j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ligature_mask) {
|
|
printf("ligatures");
|
|
for (i = 0; i < SIZEOF(ligature_names); i++)
|
|
if (ligature_mask & (1 << i))
|
|
printf(" %s", ligature_names[i]);
|
|
printf(" 0\n");
|
|
}
|
|
}
|
|
|
|
static
|
|
void read_and_output_kernpairs(File &f)
|
|
{
|
|
if (tag_info(pair_kern_tag).present) {
|
|
printf("kernpairs\n");
|
|
f.seek(tag_info(pair_kern_tag).value);
|
|
uint16 n_pairs = f.get_uint16();
|
|
for (int i = 0; i < n_pairs; i++) {
|
|
uint16 i1 = f.get_uint16();
|
|
uint16 i2 = f.get_uint16();
|
|
int16 val = int16(f.get_uint16());
|
|
if (char_table[i1].symbol_set != NO_SYMBOL_SET
|
|
&& char_table[i2].symbol_set != NO_SYMBOL_SET
|
|
&& char_table[i1].msl < msl_name_table_size
|
|
&& char_table[i2].msl < msl_name_table_size) {
|
|
for (name_list *p = msl_name_table[char_table[i1].msl];
|
|
p;
|
|
p = p->next)
|
|
for (name_list *q = msl_name_table[char_table[i2].msl];
|
|
q;
|
|
q = q->next)
|
|
printf("%s %s %d\n", p->name, q->name, scale(val));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
void output_charset()
|
|
{
|
|
require_tag(slant_tag);
|
|
double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0;
|
|
double slant = sin(slant_angle)/cos(slant_angle);
|
|
|
|
require_tag(x_height_tag);
|
|
require_tag(lower_ascent_tag);
|
|
require_tag(lower_descent_tag);
|
|
|
|
printf("charset\n");
|
|
int i;
|
|
for (i = 0; i < nchars; i++) {
|
|
uint16 msl = char_table[i].msl;
|
|
if (msl < msl_name_table_size
|
|
&& msl_name_table[msl]) {
|
|
if (char_table[i].symbol_set != NO_SYMBOL_SET) {
|
|
printf("%s\t%d,%d",
|
|
msl_name_table[msl]->name,
|
|
scale(char_table[i].width),
|
|
scale(char_table[i].ascent));
|
|
int depth = scale(- char_table[i].descent);
|
|
if (depth < 0)
|
|
depth = 0;
|
|
int italic_correction = 0;
|
|
int left_italic_correction = 0;
|
|
int subscript_correction = 0;
|
|
if (italic_flag) {
|
|
italic_correction = scale(char_table[i].right_extent
|
|
- char_table[i].width
|
|
+ italic_sep);
|
|
if (italic_correction < 0)
|
|
italic_correction = 0;
|
|
subscript_correction = int((tag_info(x_height_tag).value
|
|
* slant * .8) + .5);
|
|
if (subscript_correction > italic_correction)
|
|
subscript_correction = italic_correction;
|
|
left_italic_correction = scale(italic_sep
|
|
- char_table[i].left_extent);
|
|
}
|
|
if (subscript_correction != 0)
|
|
printf(",%d,%d,%d,%d",
|
|
depth, italic_correction, left_italic_correction,
|
|
subscript_correction);
|
|
else if (left_italic_correction != 0)
|
|
printf(",%d,%d,%d", depth, italic_correction, left_italic_correction);
|
|
else if (italic_correction != 0)
|
|
printf(",%d,%d", depth, italic_correction);
|
|
else if (depth != 0)
|
|
printf(",%d", depth);
|
|
// This is fairly arbitrary. Fortunately it doesn't much matter.
|
|
unsigned type = 0;
|
|
if (char_table[i].ascent > (tag_info(lower_ascent_tag).value*9)/10)
|
|
type |= 2;
|
|
if (char_table[i].descent < (int16(tag_info(lower_descent_tag).value)*9)/10)
|
|
type |= 1;
|
|
printf("\t%d\t%d\n",
|
|
type,
|
|
char_table[i].symbol_set*256 + char_table[i].code);
|
|
for (name_list *p = msl_name_table[msl]->next; p; p = p->next)
|
|
printf("%s\t\"\n", p->name);
|
|
}
|
|
else
|
|
warning("MSL %1 not in any of the searched symbol sets", msl);
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
void dump_tags(File &f)
|
|
{
|
|
int i;
|
|
for (i = min_tag; i <= max_tag; i++) {
|
|
enum tag_type t = tag_type(i);
|
|
if (tag_info(t).present) {
|
|
fprintf(stderr,
|
|
"%d %d %d %d\n", i, tag_info(t).type, tag_info(t).count,
|
|
tag_info(t).value);
|
|
if (tag_info(t).type == FLOAT_TYPE
|
|
&& tag_info(t).count == 1) {
|
|
f.seek(tag_info(t).value);
|
|
uint32 num = f.get_uint32();
|
|
uint32 den = f.get_uint32();
|
|
fprintf(stderr, "(%u/%u = %g)\n", num, den, (double)num/den);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
int read_map(const char *file)
|
|
{
|
|
errno = 0;
|
|
FILE *fp = fopen(file, "r");
|
|
if (!fp) {
|
|
error("can't open `%1': %2", file, strerror(errno));
|
|
return 0;
|
|
}
|
|
current_filename = file;
|
|
char buf[512];
|
|
current_lineno = 0;
|
|
while (fgets(buf, int(sizeof(buf)), fp)) {
|
|
current_lineno++;
|
|
char *ptr = buf;
|
|
while (csspace(*ptr))
|
|
ptr++;
|
|
if (*ptr == '\0' || *ptr == '#')
|
|
continue;
|
|
ptr = strtok(ptr, " \n\t");
|
|
if (!ptr)
|
|
continue;
|
|
int n;
|
|
if (sscanf(ptr, "%d", &n) != 1) {
|
|
error("bad map file");
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
if (n < 0) {
|
|
error("negative code");
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
if (n >= msl_name_table_size) {
|
|
size_t old_size = msl_name_table_size;
|
|
name_list **old_table = msl_name_table;
|
|
msl_name_table_size = n + 256;
|
|
msl_name_table = new name_list *[msl_name_table_size];
|
|
if (old_table) {
|
|
memcpy(msl_name_table, old_table, old_size*sizeof(name_list *));
|
|
a_delete old_table;
|
|
}
|
|
for (size_t i = old_size; i < msl_name_table_size; i++)
|
|
msl_name_table[i] = 0;
|
|
}
|
|
ptr = strtok(0, " \n\t");
|
|
if (!ptr) {
|
|
error("missing names");
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
for (; ptr; ptr = strtok(0, " \n\t"))
|
|
msl_name_table[n] = new name_list(ptr, msl_name_table[n]);
|
|
}
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
static
|
|
const char *xbasename(const char *s)
|
|
{
|
|
const char *b = strrchr(s, '/');
|
|
return b ? b + 1 : s;
|
|
}
|