Add 'DO NOT MODIFY' warning to generated man pages.
[libidn.git] / examples / example2.c
blobfe4417ec780c0611aa39da465934165791845813
1 /* example2.c --- Example code showing how to use punycode.
2 * Copyright (C) 2002, 2003, 2004 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
23 #include <locale.h> /* setlocale() */
26 * This file is derived from RFC 3492 written by Adam M. Costello.
28 * Disclaimer and license: Regarding this entire document or any
29 * portion of it (including the pseudocode and C code), the author
30 * makes no guarantees and is not responsible for any damage resulting
31 * from its use. The author grants irrevocable permission to anyone
32 * to use, modify, and distribute it in any way that does not diminish
33 * the rights of anyone else to use, modify, and distribute it,
34 * provided that redistributed derivative works do not contain
35 * misleading author or version information. Derivative works need
36 * not be licensed under similar terms.
40 #include <assert.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
45 #include <punycode.h>
47 /* For testing, we'll just set some compile-time limits rather than */
48 /* use malloc(), and set a compile-time option rather than using a */
49 /* command-line option. */
51 enum
53 unicode_max_length = 256,
54 ace_max_length = 256
57 static void
58 usage (char **argv)
60 fprintf (stderr,
61 "\n"
62 "%s -e reads code points and writes a Punycode string.\n"
63 "%s -d reads a Punycode string and writes code points.\n"
64 "\n"
65 "Input and output are plain text in the native character set.\n"
66 "Code points are in the form u+hex separated by whitespace.\n"
67 "Although the specification allows Punycode strings to contain\n"
68 "any characters from the ASCII repertoire, this test code\n"
69 "supports only the printable characters, and needs the Punycode\n"
70 "string to be followed by a newline.\n"
71 "The case of the u in u+hex is the force-to-uppercase flag.\n",
72 argv[0], argv[0]);
73 exit (EXIT_FAILURE);
76 static void
77 fail (const char *msg)
79 fputs (msg, stderr);
80 exit (EXIT_FAILURE);
83 static const char too_big[] =
84 "input or output is too large, recompile with larger limits\n";
85 static const char invalid_input[] = "invalid input\n";
86 static const char overflow[] = "arithmetic overflow\n";
87 static const char io_error[] = "I/O error\n";
89 /* The following string is used to convert printable */
90 /* characters between ASCII and the native charset: */
92 static const char print_ascii[] = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" " !\"#$%&'()*+,-./" "0123456789:;<=>?" "\0x40" /* at sign */
93 "ABCDEFGHIJKLMNO"
94 "PQRSTUVWXYZ[\\]^_" "`abcdefghijklmno" "pqrstuvwxyz{|}~\n";
96 int
97 main (int argc, char **argv)
99 enum punycode_status status;
100 int r;
101 size_t input_length, output_length, j;
102 unsigned char case_flags[unicode_max_length];
104 setlocale (LC_ALL, "");
106 if (argc != 2)
107 usage (argv);
108 if (argv[1][0] != '-')
109 usage (argv);
110 if (argv[1][2] != 0)
111 usage (argv);
113 if (argv[1][1] == 'e')
115 uint32_t input[unicode_max_length];
116 unsigned long codept;
117 char output[ace_max_length + 1], uplus[3];
118 int c;
120 /* Read the input code points: */
122 input_length = 0;
124 for (;;)
126 r = scanf ("%2s%lx", uplus, &codept);
127 if (ferror (stdin))
128 fail (io_error);
129 if (r == EOF || r == 0)
130 break;
132 if (r != 2 || uplus[1] != '+' || codept > (uint32_t) - 1)
134 fail (invalid_input);
137 if (input_length == unicode_max_length)
138 fail (too_big);
140 if (uplus[0] == 'u')
141 case_flags[input_length] = 0;
142 else if (uplus[0] == 'U')
143 case_flags[input_length] = 1;
144 else
145 fail (invalid_input);
147 input[input_length++] = codept;
150 /* Encode: */
152 output_length = ace_max_length;
153 status = punycode_encode (input_length, input, case_flags,
154 &output_length, output);
155 if (status == punycode_bad_input)
156 fail (invalid_input);
157 if (status == punycode_big_output)
158 fail (too_big);
159 if (status == punycode_overflow)
160 fail (overflow);
161 assert (status == punycode_success);
163 /* Convert to native charset and output: */
165 for (j = 0; j < output_length; ++j)
167 c = output[j];
168 assert (c >= 0 && c <= 127);
169 if (print_ascii[c] == 0)
170 fail (invalid_input);
171 output[j] = print_ascii[c];
174 output[j] = 0;
175 r = puts (output);
176 if (r == EOF)
177 fail (io_error);
178 return EXIT_SUCCESS;
181 if (argv[1][1] == 'd')
183 char input[ace_max_length + 2], *p, *pp;
184 uint32_t output[unicode_max_length];
186 /* Read the Punycode input string and convert to ASCII: */
188 fgets (input, ace_max_length + 2, stdin);
189 if (ferror (stdin))
190 fail (io_error);
191 if (feof (stdin))
192 fail (invalid_input);
193 input_length = strlen (input) - 1;
194 if (input[input_length] != '\n')
195 fail (too_big);
196 input[input_length] = 0;
198 for (p = input; *p != 0; ++p)
200 pp = strchr (print_ascii, *p);
201 if (pp == 0)
202 fail (invalid_input);
203 *p = pp - print_ascii;
206 /* Decode: */
208 output_length = unicode_max_length;
209 status = punycode_decode (input_length, input, &output_length,
210 output, case_flags);
211 if (status == punycode_bad_input)
212 fail (invalid_input);
213 if (status == punycode_big_output)
214 fail (too_big);
215 if (status == punycode_overflow)
216 fail (overflow);
217 assert (status == punycode_success);
219 /* Output the result: */
221 for (j = 0; j < output_length; ++j)
223 r = printf ("%s+%04lX\n",
224 case_flags[j] ? "U" : "u", (unsigned long) output[j]);
225 if (r < 0)
226 fail (io_error);
229 return EXIT_SUCCESS;
232 usage (argv);
233 return EXIT_SUCCESS; /* not reached, but quiets compiler warning */