1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29
30/*
31 *	Converts files from one char set to another
32 *
33 *	Written 11/09/87	Eddy Bell
34 *
35 */
36
37
38/*
39 *  INCLUDED and DEFINES
40 */
41#include	<stdio.h>
42#include	<fcntl.h>
43#include	<sys/systeminfo.h>
44#include	<stdlib.h>
45#include	<string.h>
46#include	<errno.h>
47/* #include	<io.h>			for microsoft c 4.0 */
48
49
50#define		CONTENTS_ASCII	0
51#define		CONTENTS_ASCII8 1
52#define		CONTENTS_ISO	2
53#define		CONTENTS_DOS	3
54#ifdef _F_BIN
55#define	DOS_BUILD 1
56#else
57#define	UNIX_BUILD 1
58#endif
59
60
61/*
62 * INCLUDES AND DEFINES
63 *
64 */
65#ifdef UNIX_BUILD
66#include <sys/types.h>
67#include	<sys/kbio.h>
68#include	<sys/time.h>
69#include	<fcntl.h>
70#include "../sys/dos_iso.h"
71#endif
72
73#ifdef DOS_BUILD
74#include <dos.h>
75#include "..\sys\dos_iso.h"
76#endif
77
78
79#define		GLOBAL
80#define		LOCAL	static
81#define		BOOL	int
82
83#define		FALSE	0
84#define		TRUE	~FALSE
85
86#define		CR	0x0D
87#define		LF	0x0A
88#define		DOS_EOF 0x1A
89
90#define		MAXLEN	1024
91
92/*
93 * FUNCTION AND VARIABLE DECLARATIONS
94 */
95static	void	error();
96static	void	usage();
97static	int	tmpfd = -1;
98/*
99 * ENTRY POINTS
100 */
101
102int
103main(int argc, char **argv)
104{
105	FILE *in_stream = NULL;
106	FILE *out_stream = NULL;
107	unsigned char tmp_buff[512];
108
109	unsigned char *src_str, *dest_str;
110	char	 *in_file_name, *out_file_name;
111	int num_read, numchar, i, j, out_len, translate_mode;
112	int same_name;
113	/* char count for fread() */
114
115	int	type;
116	int	code_page_overide; /* over ride of default codepage */
117
118	unsigned char * dos_to_iso;
119	unsigned char iso_to_dos[256];
120#ifdef UNIX_BUILD
121	int	kbdfd;
122#endif
123	char	sysinfo_str[MAXLEN];
124
125	same_name = FALSE;
126	out_file_name = (char *)0;
127
128	/*
129	 * The filename parameter is positionally dependent - in that
130	 * the dest file name must follow the source filename
131	 */
132	argv++;
133	in_stream = stdin;
134	out_stream = stdout;
135	j = 0;  /* count for file names 0 -> source 1-> dest */
136	translate_mode = CONTENTS_ISO; /* default trans mode */
137	code_page_overide = 0;
138	for (i = 1; i < argc; i++) {
139		if (*argv[0] == '-') {
140			if (argc > 1 && !strncmp(*argv, "-iso", 4)) {
141				translate_mode = CONTENTS_ISO;
142				argv++;
143			} else if (argc > 1 && !strncmp(*argv, "-7", 2)) {
144				translate_mode = CONTENTS_ASCII;
145				argv++;
146			} else if (argc > 1 && !strncmp(*argv, "-ascii", 6)) {
147				translate_mode = CONTENTS_DOS;
148				argv++;
149			} else if (argc > 1 && !strncmp(*argv, "-437", 4)) {
150				code_page_overide = CODE_PAGE_US;
151				argv++;
152			} else if (argc > 1 && !strncmp(*argv, "-850", 4)) {
153				code_page_overide = CODE_PAGE_MULTILINGUAL;
154				argv++;
155			} else if (argc > 1 && !strncmp(*argv, "-860", 4)) {
156				code_page_overide = CODE_PAGE_PORTUGAL;
157				argv++;
158			} else if (argc > 1 && !strncmp(*argv, "-863", 4)) {
159				code_page_overide = CODE_PAGE_CANADA_FRENCH;
160				argv++;
161			} else if (argc > 1 && !strncmp(*argv, "-865", 4)) {
162				code_page_overide = CODE_PAGE_NORWAY;
163				argv++;
164			} else
165				argv++;
166			continue;
167		} else {  /* not a command so must be filename */
168			switch (j) {
169				case IN_FILE:	/* open in file from cmdline */
170					in_file_name = *argv;
171					j++;  /* next file name is outfile */
172					break;
173
174				case OUT_FILE:	/* open out file from cmdline */
175					out_file_name = *argv;
176					j++;
177					break;
178
179				default:
180					usage();
181			}
182		}
183	argv++;
184	}
185
186	/* input file is specified */
187	if (j > 0) {
188		in_stream = fopen(in_file_name, "r");
189		if (in_stream == NULL)
190			error("Couldn't open input file %s.", in_file_name);
191	}
192
193	/* output file is specified */
194	if (j > 1) {
195		if (!strcmp(in_file_name, out_file_name)) {
196			/* input and output have same name */
197			if (access(out_file_name, 2))
198				error("%s not writable.", out_file_name);
199			strcpy(out_file_name, "/tmp/udXXXXXX");
200			tmpfd = mkstemp(out_file_name);
201			if (tmpfd == -1) {
202				error("Couldn't create output file %s.",
203				    out_file_name);
204			}
205			(void) close(tmpfd);
206			same_name = TRUE;
207		} else
208			same_name = FALSE;
209		out_stream = fopen(out_file_name, "w");
210		if (out_stream == NULL) {
211			(void) unlink(out_file_name);
212			error("Couldn't open output file %s.", out_file_name);
213		}
214
215	}
216#ifdef _F_BIN
217	setmode(fileno(in_stream), O_BINARY);
218	setmode(fileno(out_stream), O_BINARY);
219#endif
220
221
222#ifdef UNIX_BUILD
223	if (!code_page_overide) {
224		if (sysinfo(SI_ARCHITECTURE, sysinfo_str, MAXLEN)  < 0) {
225			fprintf(stderr,
226			    "could not obtain system information\n");
227			(void) unlink(out_file_name);
228			exit(1);
229
230		}
231		if (strcmp(sysinfo_str, "i386")) {
232			if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
233				fprintf(stderr,
234				    "could not open /dev/kbd to get "
235				    "keyboard type US keyboard assumed\n");
236			}
237			if (ioctl(kbdfd, KIOCLAYOUT, &type) < 0) {
238				fprintf(stderr,
239	"could not get keyboard type US keyboard assumed\n");
240			}
241		} else {
242			type = 0;
243		}
244		switch (type) {
245			case	0:
246			case	1:	/* United States */
247				dos_to_iso = &dos_to_iso_cp_437[0];
248			break;
249
250			case	2:	/* Belgian French */
251				dos_to_iso = &dos_to_iso_cp_437[0];
252			break;
253
254			case	3:	/* Canadian French */
255				dos_to_iso = &dos_to_iso_cp_863[0];
256			break;
257
258			case	4:	/* Danish */
259				dos_to_iso = &dos_to_iso_cp_865[0];
260			break;
261
262			case	5:	/* German */
263				dos_to_iso = &dos_to_iso_cp_437[0];
264			break;
265
266			case	6:	/* Italian */
267				dos_to_iso = &dos_to_iso_cp_437[0];
268			break;
269
270			case	7:	/* Netherlands Dutch */
271				dos_to_iso = &dos_to_iso_cp_437[0];
272			break;
273
274			case	8:	/* Norwegian */
275				dos_to_iso = &dos_to_iso_cp_865[0];
276			break;
277
278			case	9:	/* Portuguese */
279				dos_to_iso = &dos_to_iso_cp_860[0];
280			break;
281
282			case	10:	/* Spanish */
283				dos_to_iso = &dos_to_iso_cp_437[0];
284			break;
285
286			case	11:	/* Swedish Finnish */
287				dos_to_iso = &dos_to_iso_cp_437[0];
288			break;
289
290			case	12:	/* Swiss French */
291				dos_to_iso = &dos_to_iso_cp_437[0];
292			break;
293
294			case	13:	/* Swiss German */
295				dos_to_iso = &dos_to_iso_cp_437[0];
296			break;
297
298			case	14:	/* United Kingdom */
299				dos_to_iso = &dos_to_iso_cp_437[0];
300
301			break;
302
303			default:
304				dos_to_iso = &dos_to_iso_cp_437[0];
305			break;
306		}
307	} else {
308		switch (code_page_overide) {
309			case CODE_PAGE_US:
310				dos_to_iso = &dos_to_iso_cp_437[0];
311			break;
312
313			case CODE_PAGE_MULTILINGUAL:
314				dos_to_iso = &dos_to_iso_cp_850[0];
315			break;
316
317			case CODE_PAGE_PORTUGAL:
318				dos_to_iso = &dos_to_iso_cp_860[0];
319			break;
320
321			case CODE_PAGE_CANADA_FRENCH:
322				dos_to_iso = &dos_to_iso_cp_863[0];
323			break;
324
325			case CODE_PAGE_NORWAY:
326				dos_to_iso = &dos_to_iso_cp_865[0];
327			break;
328		}
329	}
330#endif
331#ifdef DOS_BUILD
332	if (!code_page_overide) {
333		{
334		union REGS regs;
335		regs.h.ah = 0x66;	/* get/set global code page */
336		regs.h.al = 0x01;		/* get */
337		intdos(&regs, &regs);
338		type = regs.x.bx;
339		}
340		switch (type) {
341			case	437:	/* United States */
342				dos_to_iso = &dos_to_iso_cp_437[0];
343			break;
344
345			case	850:	/* Multilingual */
346				dos_to_iso = &dos_to_iso_cp_850[0];
347			break;
348
349			case	860:	/* Portuguese */
350				dos_to_iso = &dos_to_iso_cp_860[0];
351			break;
352
353			case	863:	/* Canadian French */
354				dos_to_iso = &dos_to_iso_cp_863[0];
355			break;
356
357			case	865:	/* Danish */
358				dos_to_iso = &dos_to_iso_cp_865[0];
359			break;
360
361			default:
362				dos_to_iso = &dos_to_iso_cp_437[0];
363			break;
364		}
365	} else {
366		switch (code_page_overide) {
367			case CODE_PAGE_US:
368				dos_to_iso = &dos_to_iso_cp_437[0];
369			break;
370
371			case CODE_PAGE_MULTILINGUAL:
372				dos_to_iso = &dos_to_iso_cp_850[0];
373			break;
374
375			case CODE_PAGE_PORTUGAL:
376				dos_to_iso = &dos_to_iso_cp_860[0];
377			break;
378
379			case CODE_PAGE_CANADA_FRENCH:
380				dos_to_iso = &dos_to_iso_cp_863[0];
381			break;
382
383			case CODE_PAGE_NORWAY:
384				dos_to_iso = &dos_to_iso_cp_865[0];
385			break;
386		}
387	}
388
389#endif
390	for (i = 0; i <= 255; i++) {
391		iso_to_dos[dos_to_iso[i]] = i;
392	}
393
394	/*
395	 * While not EOF, read in chars and send them to out_stream
396	 * if current char is not a CR.
397	 */
398
399    do {
400		num_read = fread(&tmp_buff[100], 1, 100, in_stream);
401		i = 0;
402		out_len = 0;
403		src_str = &tmp_buff[100];
404		dest_str = &tmp_buff[0];
405		switch (translate_mode) {
406			case CONTENTS_ISO:
407				{
408				while (i++ != num_read) {
409					if (*src_str == '\n') {
410						*dest_str++ = '\r';
411						out_len++;
412						}
413					out_len++;
414					*dest_str++ = iso_to_dos[*src_str++];
415					}
416				}
417				break;
418
419			case CONTENTS_ASCII:
420				while (i++ != num_read) {
421					if (*src_str > 127) {
422						*dest_str++ =
423						    (unsigned char) ' ';
424						src_str++;
425						out_len++;
426					} else {
427						if (*src_str == '\n') {
428							*dest_str++ = '\r';
429							out_len++;
430						}
431						*dest_str++ = *src_str++;
432						out_len++;
433					}
434				}
435				break;
436
437			case CONTENTS_DOS:
438				{
439				while (i++ != num_read) {
440					if (*src_str == '\n') {
441						*dest_str++ = '\r';
442						out_len++;
443						}
444					*dest_str++ =	*src_str++;
445					out_len++;
446					}
447				}
448				break;
449			}
450		if (out_len && out_len != fwrite(&tmp_buff[0], 1, out_len,
451		    out_stream))
452			error("Error writing to %s.", out_file_name);
453
454		} while (!feof(in_stream));
455
456#ifdef CTRL_Z_ON_EOF
457	tmp_buff[0] = 26;
458	fwrite(&tmp_buff[0], 1, 1, out_stream);
459#endif
460	fclose(out_stream);
461	fclose(in_stream);
462	if (same_name) {
463		unlink(in_file_name);
464		in_stream = fopen(out_file_name, "r");
465		out_stream = fopen(in_file_name, "w");
466#ifdef _F_BIN
467		setmode(fileno(in_stream), O_BINARY);
468		setmode(fileno(out_stream), O_BINARY);
469#endif
470		while ((num_read = fread(tmp_buff, 1, sizeof (tmp_buff),
471		    in_stream)) != 0) {
472			if (num_read != fwrite(tmp_buff, 1, num_read,
473			    out_stream))
474				error("Error writing to %s.", in_file_name);
475		}
476		fclose(out_stream);
477		fclose(in_stream);
478		unlink(out_file_name);
479	}
480	return (0);
481}
482
483void
484error(format, args)
485	char	*format;
486	char	*args;
487{
488	fprintf(stderr, "unix2dos: ");
489	fprintf(stderr, format, args);
490	fprintf(stderr, "  %s.\n", strerror(errno));
491	exit(1);
492}
493
494void
495usage()
496{
497	fprintf(stderr,
498	    "usage: unix2dos [ -ascii ] [ -iso ] [ -7 ] [ originalfile [ convertedfile ] ]\n");
499	exit(1);
500}
501