2 * Copyright 2010-2012 Chris Spiegel.
4 * This file is part of Bocfel.
6 * Bocfel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version
8 * 2 or 3, as published by the Free Software Foundation.
10 * Bocfel is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Bocfel. If not, see <http://www.gnu.org/licenses/>.
20 #define _XOPEN_SOURCE 600
30 /* OS-specific functions should all be collected in this file for
31 * convenience. A sort of poor-man’s “reverse” inheritance is used: for
32 * each function that a particular operating system provides, it should
33 * #define a macro of the same name. At the end of the file, a generic
34 * function is provided for each function that has no associated macro
37 * The functions required are as follows:
39 * long zterp_os_filesize(FILE *fp)
41 * Return the size of the file referred to by fp. It is safe to assume
42 * that the file is opened in binary mode. The file position indicator
43 * need not be maintained. If the size of the file is larger than
44 * LONG_MAX, -1 should be returned.
46 * int zterp_os_have_unicode(void)
48 * The main purpose behind this function is to indicate whether
49 * transcripts will be written in UTF-8 or Latin-1. This is, of course,
50 * not necessarily an OS matter, but I’ve run into some issues with
51 * UTF-8 and Windows (at least through Wine), so I want to be as
52 * sensible as I can with the defaults. The user is able to override
53 * this value if he so desires.
54 * If a Glk build is not being used, this function also serves to
55 * indicate whether all I/O, not just transcripts, should be UTF-8 or
56 * not. Glk libraries are able to be queried as to their support for
57 * Unicode so there is no need to make assumptions in that case.
59 * void zterp_os_rcfile(char *s, size_t n)
61 * Different operating systems have different ideas about where
62 * configuration data should be stored; this function will copy a
63 * suitable value for the bocfel configuration file into the buffer s
64 * which is n bytes long.
66 * void zterp_os_reopen_binary(FILE *fp)
68 * Writing UTF-8 requires that no mangling be done, such as might happen
69 * when a stream is opened in text mode. This function should, if
70 * necessary, set the mode on the file pointer in fp to be binary.
72 * The following functions are useful for non-Glk builds only. They
73 * provide for some handling of screen functions that is normally taken
76 * void zterp_os_get_screen_size(unsigned *w, unsigned *h)
78 * The size of the terminal, if known, is written into *w (width) and *h
79 * (height). If terminal size is unavalable, nothing should be written.
81 * void zterp_os_init_term(void)
83 * If something special needs to be done to prepare the terminal for
84 * output, it should be done here. This function is called once at
87 * int zterp_os_have_style(int style)
89 * This should return true if the provided style (see style.h for valid
90 * STYLE_ values) is available. It is safe to assume that styles will
91 * not be combined; e.g. this will not be called as:
92 * zterp_os_have_style(STYLE_BOLD | STYLE_ITALIC);
94 * int zterp_os_have_colors(void)
96 * Returns true if the terminal supports colors.
98 * void zterp_os_set_style(int style, int fg, int bg)
100 * Set both a style and foreground/background color. Any previous
101 * settings should be ignored; for example, if the last call to
102 * zterp_os_set_style() turned on italics and the current call sets
103 * bold, the result should be bold, not bold italic.
104 * Unlike in zterp_os_have_style(), here styles may be combined. See
105 * the Unix implementation for a reference.
106 * The colors are Z-machine colors (see §8.3.1), with the following
107 * note: the only color values that will ever be passed in are 1–9.
114 #include <sys/stat.h>
116 long zterp_os_filesize(FILE *fp)
121 if(fd == -1 || fstat(fd, &buf) == -1 || !S_ISREG(buf.st_mode) || buf.st_size > LONG_MAX) return -1;
125 #define zterp_os_filesize
127 int zterp_os_have_unicode(void)
131 #define zterp_os_have_unicode
133 void zterp_os_rcfile(char *s, size_t n)
135 snprintf(s, n, "%s/.bocfelrc", getenv("HOME") != NULL ? getenv("HOME") : ".");
137 #define zterp_os_rcfile
141 #include <sys/ioctl.h>
145 void zterp_os_get_screen_size(unsigned *w, unsigned *h)
147 struct winsize winsize;
149 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) == 0)
155 #define zterp_os_get_screen_size
158 static const char *ital = NULL, *rev = NULL, *bold = NULL, *none = NULL;
159 static char *fg_string = NULL, *bg_string = NULL;
160 static int have_colors = 0;
161 void zterp_os_init_term(void)
163 if(setupterm(NULL, STDIN_FILENO, NULL) != OK) return;
165 /* prefer italics over underline for emphasized text */
166 ital = tgetstr("ZH", NULL);
167 if(ital == NULL) ital = tgetstr("us", NULL);
168 rev = tgetstr("mr", NULL);
169 bold = tgetstr("md", NULL);
170 none = tgetstr("me", NULL);
172 fg_string = tgetstr("AF", NULL);
173 bg_string = tgetstr("AB", NULL);
175 have_colors = none != NULL && fg_string != NULL && bg_string != NULL;
177 #define zterp_os_init_term
179 int zterp_os_have_style(int style)
181 if(none == NULL) return 0;
183 if (style == STYLE_ITALIC) return ital != NULL;
184 else if(style == STYLE_REVERSE) return rev != NULL;
185 else if(style == STYLE_BOLD) return bold != NULL;
186 else if(style == STYLE_NONE) return none != NULL;
190 #define zterp_os_have_style
192 int zterp_os_have_colors(void)
196 #define zterp_os_have_colors
198 void zterp_os_set_style(int style, int fg, int bg)
200 /* If the terminal cannot be reset, nothing can be used. */
201 if(none == NULL) return;
205 if((style & STYLE_ITALIC) && ital != NULL) putp(ital);
206 if((style & STYLE_REVERSE) && rev != NULL) putp(rev);
207 if((style & STYLE_BOLD) && bold != NULL) putp(bold);
211 if(fg > 1) putp(tparm(fg_string, fg - 2, 0, 0, 0, 0, 0, 0, 0, 0));
212 if(bg > 1) putp(tparm(bg_string, bg - 2, 0, 0, 0, 0, 0, 0, 0, 0));
215 #define zterp_os_set_style
218 /*********************
219 * Windows functions *
220 *********************/
221 #elif defined(ZTERP_WIN32)
222 void zterp_os_rcfile(char *s, size_t n)
226 p = getenv("APPDATA");
227 if(p == NULL) p = getenv("LOCALAPPDATA");
228 if(p == NULL) p = ".";
230 snprintf(s, n, "%s\\bocfel.ini", p);
232 #define zterp_os_rcfile
236 /*********************
237 * Generic functions *
238 *********************/
239 #ifndef zterp_os_filesize
240 long zterp_os_filesize(FILE *fp)
242 /* Assume fseek() can seek to the end of binary streams. */
243 if(fseek(fp, 0, SEEK_END) == -1) return -1;
249 #ifndef zterp_os_have_unicode
250 int zterp_os_have_unicode(void)
256 #ifndef zterp_os_rcfile
257 void zterp_os_rcfile(char *s, size_t n)
259 snprintf(s, n, "bocfelrc");
263 /* When UTF-8 output is enabled, special translation of characters (e.g.
264 * newline) should not be done. Theoretically this function exists to
265 * set stdin/stdout to binary mode, if necessary. Unix makes no
266 * text/binary distinction, but Windows does. I’m under the impression
267 * that there is a setmode() function that should be able to do this,
268 * but my knowledge of Windows is so small that I do not want to do much
269 * more than I have, lest I completely break Windows support—assuming it
271 * freopen() should be able to do this, but with my testing under Wine,
272 * no text gets output in such a case.
274 #ifndef zterp_os_reopen_binary
275 void zterp_os_reopen_binary(FILE *fp)
281 #ifndef zterp_os_get_screen_size
282 void zterp_os_get_screen_size(unsigned *w, unsigned *h)
287 #ifndef zterp_os_init_term
288 void zterp_os_init_term(void)
293 #ifndef zterp_os_have_style
294 int zterp_os_have_style(int style)
300 #ifndef zterp_os_have_colors
301 int zterp_os_have_colors(void)
307 #ifndef zterp_os_set_style
308 void zterp_os_set_style(int style, int fg, int bg)