]> git.gir.st - base65536.git/blob - main.c
Correctly handle fopen() return value
[base65536.git] / main.c
1 /* base65536 en- and decoder with usage similar to GNU's base64.
2 (C) 2016 Tobias Girstmair, http://isticktoit.net/
3 Released under the GNU GPL v3. See LICENSE for details. */
4
5 #define _XOPEN_SOURCE
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include "base65536.h"
12
13 #define VERSION "0.2"
14
15 #define DEFAULT_WRAP 72
16
17 #define COPYRIGHT "(C) 2016 Tobias Girstmair, GPLv3"
18 #define HELP_TEXT \
19 "Usage: %s [OPTION]... [FILE]\n"\
20 "Options: -d (decode), -i (ignore-garbage), -w COLS (wrap, default %d) "\
21 "-v (version) -h (help)\n"
22
23 struct ops {
24 FILE* f;
25 int d; /*decode*/
26 int i; /*ignore-garbage*/
27 int w; /*wrap*/
28 };
29
30 void do_encode (FILE* in, FILE* out, int wrap_column);
31 void do_decode (FILE* in, FILE* out, int ignore_garbage);
32
33 int main (int argc, char** argv) {
34 struct ops op = {stdin, 0, 0, DEFAULT_WRAP};
35 int opt;
36
37 opterr=0; /* suppress default error messages */
38 while ( (opt = getopt(argc, argv, "diw:vh")) != -1) {
39 switch (opt) {
40 case 'd': op.d = 1; break;
41 case 'i': op.i = 1; break;
42 case 'w': op.w = atoi (optarg); break;
43 case 'v':
44 fprintf (stderr, "base65536 %s\n%s\n", VERSION, COPYRIGHT);
45 return 0;
46 case 'h':
47 fprintf (stderr, HELP_TEXT, argv[0], DEFAULT_WRAP);
48 return 0;
49 default:
50 fprintf (stderr, "unknown option '-%c'.\n", optopt);
51 return 1;
52 }
53 }
54 if (argc-optind > 1) {
55 fprintf (stderr, "%s: extra operand '%s'. \n", argv[0], argv[argc-1]);
56 return 1;
57 } else if (optind < argc) {
58 if (strcmp (argv [optind], "-") != 0)
59 op.f = fopen (argv[optind], "rb");
60 if (op.f == NULL) {
61 fprintf (stderr, "Impossible to open the file %s: %s\n", argv[optind], strerror(errno));
62 return 1;
63 }
64 }
65
66 if (op.d) {
67 do_decode (op.f, stdout, op.i);
68 } else {
69 do_encode (op.f, stdout, op.w);
70 }
71
72 if (op.f != stdin) fclose (op.f);
73
74 return 0;
75 }
76
77
78 void do_encode (FILE* in, FILE* out, int wrap_column) {
79 int in_char[2];
80 char out_utf8[5];
81 int unicode_cp;
82 long cnt = 0;
83
84 while (1) {
85 if ((in_char[0] = getc(in)) == EOF) break;
86 in_char[1] = getc(in);
87
88 unicode_cp = base65536_encode_char (in_char);
89 codepoint_to_utf8 (unicode_cp, out_utf8);
90 fprintf (out, "%s%s", wrap_column&&!(cnt%wrap_column)&&cnt?"\n":"", out_utf8);
91 cnt++;
92 if (in_char[1] == EOF) break;
93 }
94 printf ("\n");
95 }
96
97 void do_decode (FILE* in, FILE* out, int ignore_garbage) {
98 int out_char[2];
99 char in_utf8[5];
100 int unicode_cp;
101 int chars_written;
102
103 while (1) {
104 for (int i = 0; i < 5; i++) {
105 int c = getc (in);
106 if (c == EOF) {
107 return;
108 } else if (i != 0 && c < 0x80) { /* start of new asciichar */
109 ungetc (c, in);
110 in_utf8[i] = '\0';
111 break;
112 } else if (i != 0 && c >= 0xc0) { /* start of new utf8char */
113 ungetc (c, in);
114 in_utf8[i] = '\0';
115 break;
116 }
117 in_utf8[i] = c;
118 }
119 unicode_cp = utf8_to_codepoint (in_utf8);
120 /* ignore ascii-chars, because base65k won't map to those (but
121 whitespace may be added by the encoder / medium) */
122 if (unicode_cp < 0x80) continue;
123
124 chars_written = base65536_decode_char (unicode_cp, out_char);
125 if (chars_written > 0) {
126 fputc (out_char[0], out);
127 if (chars_written ==2) fputc (out_char[1], out);
128 } else {
129 if (!ignore_garbage) {
130 fprintf (stderr, "Unrecognized glyph %s\n", in_utf8);
131 return;
132 }
133 }
134 }
135 }
Imprint / Impressum