1 /* otflist.c -- List OpenType fonts.
2 
3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4   National Institute of Advanced Industrial Science and Technology (AIST)
5   Registration Number H15PRO167
6 
7 This file is part of libotf.
8 
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13 
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA.  */
23 
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 
30 #include <ft2build.h>
31 #include FT_FREETYPE_H
32 
33 #include "config.h"
34 #ifdef HAVE_ALLOCA_H
35 #include <alloca.h>
36 #endif
37 
38 #include <otf.h>
39 
40 /* Format MSG by FMT and print the result to the stderr, and exit.  */
41 
42 #define FATAL_ERROR(fmt, arg)	\
43   do {				\
44     fprintf (stderr, fmt, arg);	\
45     exit (1);			\
46   } while (0)
47 
48 
49 void
print_tag(OTF_Tag tag)50 print_tag (OTF_Tag tag)
51 {
52   char name[5];
53 
54   OTF_tag_name (tag, name);
55   printf ("%s", name);
56 }
57 
58 void
print_gsub_gpos_info(OTF * otf,char * table)59 print_gsub_gpos_info (OTF *otf, char *table)
60 {
61   int i, j;
62 
63   if (OTF_get_table (otf, table) == 0)
64     {
65       OTF_ScriptList *scripts;
66       OTF_FeatureList *features;
67 
68       if (! strcmp (table, "GSUB"))
69 	scripts = &otf->gsub->ScriptList, features = &otf->gsub->FeatureList;
70       else
71 	scripts = &otf->gpos->ScriptList, features = &otf->gpos->FeatureList;
72 
73       printf ("  %s scripts: ", table);
74       for (i = 0; i < scripts->ScriptCount; i++)
75 	{
76 	  OTF_Script *script = scripts->Script + i;
77 
78 	  if (i > 0)
79 	    printf (", ");
80 	  print_tag (script->ScriptTag);
81 	  if (script->LangSysCount > 0)
82 	    {
83 	      printf (" (");
84 	      for (j = 0; j < script->LangSysCount; j++)
85 		{
86 		  if (j > 0)
87 		    printf (", ");
88 		  print_tag (script->LangSysRecord[j].LangSysTag);
89 		}
90 	      printf (")");
91 	    }
92 	}
93       printf ("\n");
94 
95       printf ("  %s features: ", table);
96       for (i = 0; i < features->FeatureCount; i++)
97 	{
98 	  if (i > 0)
99 	    printf (",");
100 	  print_tag (features->Feature[i].FeatureTag);
101 	}
102       printf ("\n");
103     }
104 }
105 void
help_and_exit(char * prog)106 help_and_exit (char *prog)
107 {
108   printf ("otflist %s\n", LIBOTF_VERSION);
109   printf ("Usage: %s [-l] [-h] [DIR]\n", prog);
110   printf ("List information about OpenType font files in the directory DIR.\n");
111   printf ("It actually lists all fonts that can be handled by Freetype.\n");
112   printf ("  -h		print this help, then exit\n");
113   printf ("  -l		use a long listing mode\n");
114   exit (0);
115 }
116 
117 int
filter(const struct dirent * direntry)118 filter (const struct dirent *direntry)
119 {
120   int len = strlen (direntry->d_name);
121   const char *ext = direntry->d_name + (len - 4);
122 
123   return (len >= 5
124 	  && (! strncmp (ext, ".ttf", 4)
125 	      || ! strncmp (ext, ".TTF", 4)
126 	      || ! strncmp (ext, ".ttc", 4)
127 	      || ! strncmp (ext, ".TTC", 4)
128 	      || ! strncmp (ext, ".otf", 4)
129 	      || ! strncmp (ext, ".OTF", 4)
130 	      || ! strncmp (ext, ".PFA", 4)
131 	      || ! strncmp (ext, ".pfa", 4)
132 	      || ! strncmp (ext, ".PFB", 4)
133 	      || ! strncmp (ext, ".pfb", 4)));
134 }
135 
136 int dir_index = 0;
137 
138 #ifdef HAVE_SCANDIR
139 
140 struct dirent **namelist = NULL;
141 int num_files = 0;
142 
143 char *
next_file(char * dirname)144 next_file (char *dirname)
145 {
146   if (dir_index == 0)
147     {
148 #ifdef HAVE_ALPHASORT
149       num_files = scandir (".", &namelist, filter, alphasort);
150 #else
151       num_files = scandir (".", &namelist, filter, NULL);
152 #endif
153     }
154   if (dir_index == num_files)
155     return NULL;
156   return namelist[dir_index++]->d_name;
157 }
158 
159 #else  /* not HAVE_SCANDIR */
160 
161 DIR *dirp;
162 
163 char *
next_file(char * dirname)164 next_file (char *dirname)
165 {
166   struct dirent *dirent;
167 
168   if (dir_index == 0)
169     dirp = opendir (dirname);
170   while ((dirent = readdir (dirp))
171 	 && (strcmp (dirent->d_name, ".") == 0
172 	     || strcmp (dirent->d_name, "..") == 0));
173   if (! dirent)
174     return NULL;
175   dir_index++;
176   return dirent->d_name;
177 }
178 
179 #endif /* not HAVE_SCANDIR */
180 
181 int
main(int argc,char ** argv)182 main (int argc, char **argv)
183 {
184   FT_Library ft_library;
185   FT_Face face;
186   char *filename;
187   int long_format = 0;
188   int i;
189 
190   if (FT_Init_FreeType (&ft_library))
191     FATAL_ERROR ("%s\n", "!! Freetype initialization failed.");
192 
193   if (argc > 1)
194     {
195       if (! strcmp (argv[1], "-h") || ! strcmp (argv[1], "--help"))
196 	help_and_exit (argv[0]);
197       if (! strcmp (argv[1], "-l"))
198 	long_format = 1, argc--, argv++;
199     }
200   if (argc == 2)
201     {
202       if (chdir (argv[1]) < 0)
203 	FATAL_ERROR ("Can't change directory to %s\n", argv[1]);
204     }
205 
206   while ((filename = next_file (".")) != NULL)
207     {
208       if (! FT_New_Face (ft_library, filename, 0, &face))
209 	{
210 	  OTF *otf = OTF_open (filename);
211 	  char *name, *family = NULL, *style = NULL;
212 
213 	  if (otf && OTF_get_table (otf, "name") == 0)
214 	    {
215 	      if (! (family = otf->name->name[16]))
216 		family = otf->name->name[1];
217 	      if (! (style = otf->name->name[17]))
218 		style = otf->name->name[2];
219 	    }
220 	  if (! family)
221 	    family = face->family_name;
222 	  if (! style)
223 	    style = face->style_name;
224 
225 	  name = alloca (strlen (filename)
226 			 + strlen (family)
227 			 + 4);
228 	  sprintf (name, "%s (%s)", filename, family);
229 	  printf ("%-40s %s", name, style);
230 	  for (i = 0; i < face->num_charmaps; i++)
231 	    printf (" %d-%d", face->charmaps[i]->platform_id,
232 		    face->charmaps[i]->encoding_id);
233 	  printf ("\n");
234 	  if (otf && long_format)
235 	    {
236 	      print_gsub_gpos_info (otf, "GSUB");
237 	      print_gsub_gpos_info (otf, "GPOS");
238 	    }
239 	  if (otf)
240 	    OTF_close (otf);
241 	}
242       else
243 	{
244 	  printf ("%s fail to open\n", filename);
245 	}
246     }
247   exit (0);
248 }
249