1 /*
2  * Copyright (c) 2019 Georg Brein. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <wchar.h>
35 #include <wctype.h>
36 
37 #include "tnylpo.h"
38 
39 
40 /*
41  * return base name of Unix path
42  */
43 const char *
base_name(const char * path)44 base_name(const char *path) {
45 	const char *cp = path + strlen(path);
46 	while (cp != path && *(cp - 1) != '/') cp--;
47 	return cp;
48 }
49 
50 
51 /*
52  * allocate memory, scream and die if there is no more memory available
53  */
54 void *
alloc(size_t s)55 alloc(size_t s) {
56 	void *vp = malloc(s);
57 	if (! vp) {
58 		perr("out of memory");
59 		exit(EXIT_FAILURE);
60 	}
61 	return vp;
62 }
63 
64 
65 /*
66  * same, but reallocates memory
67  */
resize(void * vp,size_t s)68 void *resize(void *vp, size_t s) {
69 	void *tp = realloc(vp, s);
70 	if (! tp) {
71 		perr("out of memory");
72 		exit(EXIT_FAILURE);
73 	}
74 	return tp;
75 }
76 
77 
78 /*
79  * convert a Unix character to the CP/M character set
80  * returns (-1) if the character cannot converted, and the 8-bit
81  * character value otherwise
82  */
83 int
to_cpm(wchar_t c)84 to_cpm(wchar_t c) {
85 	int i;
86 	wchar_t **cs;
87 	/*
88 	 * control characters are passed through unaltered
89 	 */
90 	if ((c >= 0x00 && c <= 0x1f) || c == 0x7f) return (int) c;
91 	/*
92 	 * primary or alternate character set?
93 	 */
94 	cs = charset ? conf_alt_charset : conf_charset;
95 	/*
96 	 * check the potentially printable character range (skipping DEL)
97 	 */
98 	for (i = 0x20; i < 0x100; i++) {
99 		if (i == 0x7f || ! cs[i]) continue;
100 		if (cs[i][0] == c) return i;
101 	}
102 	return (-1);
103 }
104 
105 
106 /*
107  * convert a CP/M character to a Unix character
108  * returns (wint_t) (-1) if the character cannot be translated and there
109  * is no representation for unprintable characters defined, and the
110  * Unix wchar otherwise
111  */
112 wint_t
from_cpm(unsigned char c)113 from_cpm(unsigned char c) {
114 	wchar_t **cs;
115 	/*
116 	 * control characters are passed through unaltered
117 	 */
118 	if (c <= 0x1f /* US */ || c == 0x7f /* DEL */) return c;
119 	/*
120 	 * primary or alternate character set?
121 	 */
122 	cs = charset ? conf_alt_charset : conf_charset;
123 	if (! cs[c]) {
124 		/*
125 		 * replace untranslateable characters by the
126 		 * "unprintable" character, if one is defined
127 		 */
128 		if (conf_unprintable) return conf_unprintable[0];
129 		return (-1);
130 	}
131 	return cs[c][0];
132 }
133 
134 
135 /*
136  * same as from_cpm(), but characters in the range 0x5e ... 0x7e are
137  * mapped to 0x7f, 0x1f, 0x00 ... 0x1e to implement the "graphic
138  * character set" feature of the VT52
139  */
140 wint_t
from_graph(unsigned char c)141 from_graph(unsigned char c) {
142 	wchar_t **cs;
143 	/*
144 	 * control characters are passed through unaltered
145 	 */
146 	if (c <= 0x1f /* US */ || c == 0x7f /* DEL */) return c;
147 	/*
148 	 * map 0x5e ... 0x7e to the "graphic" positions
149 	 */
150 	if (c >= 0x60 /* @ */ && c <= 0x7e /* ~ */) {
151 		c -= 0x60; /* @ --> NUL; ~ --> RS */
152 	} else if (c == 0x5f /* _ */) {
153 		c = 0x1f /* US */;
154 	} else if (c == 0x5e /* ^ */) {
155 		c = 0x7f /* DEL */;
156 	}
157 	/*
158 	 * primary or alternate character set?
159 	 */
160 	cs = charset ? conf_alt_charset : conf_charset;
161 	if (! cs[c]) {
162 		if (conf_unprintable) return conf_unprintable[0];
163 		return (-1);
164 	}
165 	return cs[c][0];
166 }
167