Include internal.h for uint32_t and use it.
[libidn.git] / example2.c
blob6f0ce4a1374468e4bae1de68aff9a5c1a08fe622
1 /* example2.c Example code showing how to use punycode.
2 * Copyright (C) 2002, 2003 Simon Josefsson
3 * Copyright (C) 2002 Adam M. Costello
5 * This file is part of GNU Libidn.
7 * GNU Libidn is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * GNU Libidn is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with GNU Libidn; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * This file is derived from RFC 3492 written by Adam M. Costello.
26 * Disclaimer and license: Regarding this entire document or any
27 * portion of it (including the pseudocode and C code), the author
28 * makes no guarantees and is not responsible for any damage resulting
29 * from its use. The author grants irrevocable permission to anyone
30 * to use, modify, and distribute it in any way that does not diminish
31 * the rights of anyone else to use, modify, and distribute it,
32 * provided that redistributed derivative works do not contain
33 * misleading author or version information. Derivative works need
34 * not be licensed under similar terms.
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include "punycode.h"
45 /* For testing, we'll just set some compile-time limits rather than */
46 /* use malloc(), and set a compile-time option rather than using a */
47 /* command-line option. */
49 enum
51 unicode_max_length = 256,
52 ace_max_length = 256
55 static void
56 usage (char **argv)
58 fprintf (stderr,
59 "\n"
60 "%s -e reads code points and writes a Punycode string.\n"
61 "%s -d reads a Punycode string and writes code points.\n"
62 "\n"
63 "Input and output are plain text in the native character set.\n"
64 "Code points are in the form u+hex separated by whitespace.\n"
65 "Although the specification allows Punycode strings to contain\n"
66 "any characters from the ASCII repertoire, this test code\n"
67 "supports only the printable characters, and needs the Punycode\n"
68 "string to be followed by a newline.\n"
69 "The case of the u in u+hex is the force-to-uppercase flag.\n",
70 argv[0], argv[0]);
71 exit (EXIT_FAILURE);
74 static void
75 fail (const char *msg)
77 fputs (msg, stderr);
78 exit (EXIT_FAILURE);
81 static const char too_big[] =
82 "input or output is too large, recompile with larger limits\n";
83 static const char invalid_input[] = "invalid input\n";
84 static const char overflow[] = "arithmetic overflow\n";
85 static const char io_error[] = "I/O error\n";
88 /* The following string is used to convert printable */
89 /* characters between ASCII and the native charset: */
91 static const char print_ascii[] =
92 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
93 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
94 " !\"#$%&'()*+,-./"
95 "0123456789:;<=>?"
96 "\x40""ABCDEFGHIJKLMNO"
97 "PQRSTUVWXYZ[\\]^_" "`abcdefghijklmno" "pqrstuvwxyz{|}~\n";
101 main (int argc, char **argv)
103 int status;
104 int r;
105 size_t input_length, output_length, j;
106 unsigned char case_flags[unicode_max_length];
108 if (argc != 2)
109 usage (argv);
110 if (argv[1][0] != '-')
111 usage (argv);
112 if (argv[1][2] != 0)
113 usage (argv);
115 if (argv[1][1] == 'e')
117 unsigned long input[unicode_max_length];
118 unsigned long codept;
119 char output[ace_max_length + 1], uplus[3];
120 int c;
122 /* Read the input code points: */
124 input_length = 0;
126 for (;;)
128 r = scanf ("%2s%lx", uplus, &codept);
129 if (ferror (stdin))
130 fail (io_error);
131 if (r == EOF || r == 0)
132 break;
134 if (r != 2 || uplus[1] != '+' || codept > (unsigned long) -1)
136 fail (invalid_input);
139 if (input_length == unicode_max_length)
140 fail (too_big);
142 if (uplus[0] == 'u')
143 case_flags[input_length] = 0;
144 else if (uplus[0] == 'U')
145 case_flags[input_length] = 1;
146 else
147 fail (invalid_input);
149 input[input_length++] = codept;
152 /* Encode: */
154 output_length = ace_max_length;
155 status = punycode_encode (input_length, input, case_flags,
156 &output_length, output);
157 if (status == PUNYCODE_BAD_INPUT)
158 fail (invalid_input);
159 if (status == PUNYCODE_BIG_OUTPUT)
160 fail (too_big);
161 if (status == PUNYCODE_OVERFLOW)
162 fail (overflow);
163 assert (status == PUNYCODE_SUCCESS);
165 /* Convert to native charset and output: */
167 for (j = 0; j < output_length; ++j)
169 c = output[j];
170 assert (c >= 0 && c <= 127);
171 if (print_ascii[c] == 0)
172 fail (invalid_input);
173 output[j] = print_ascii[c];
176 output[j] = 0;
177 r = puts (output);
178 if (r == EOF)
179 fail (io_error);
180 return EXIT_SUCCESS;
183 if (argv[1][1] == 'd')
185 char input[ace_max_length + 2], *p, *pp;
186 unsigned long output[unicode_max_length];
188 /* Read the Punycode input string and convert to ASCII: */
190 fgets (input, ace_max_length + 2, stdin);
191 if (ferror (stdin))
192 fail (io_error);
193 if (feof (stdin))
194 fail (invalid_input);
195 input_length = strlen (input) - 1;
196 if (input[input_length] != '\n')
197 fail (too_big);
198 input[input_length] = 0;
200 for (p = input; *p != 0; ++p)
202 pp = strchr (print_ascii, *p);
203 if (pp == 0)
204 fail (invalid_input);
205 *p = pp - print_ascii;
208 /* Decode: */
210 output_length = unicode_max_length;
211 status = punycode_decode (input_length, input, &output_length,
212 output, case_flags);
213 if (status == PUNYCODE_BAD_INPUT)
214 fail (invalid_input);
215 if (status == PUNYCODE_BIG_OUTPUT)
216 fail (too_big);
217 if (status == PUNYCODE_OVERFLOW)
218 fail (overflow);
219 assert (status == PUNYCODE_SUCCESS);
221 /* Output the result: */
223 for (j = 0; j < output_length; ++j)
225 r = printf ("%s+%04lX\n",
226 case_flags[j] ? "U" : "u", (unsigned long) output[j]);
227 if (r < 0)
228 fail (io_error);
231 return EXIT_SUCCESS;
234 usage (argv);
235 return EXIT_SUCCESS; /* not reached, but quiets compiler warning */