libidn: Example 2
1
1 9.2 Example 2
1 =============
1
1 This example demonstrates how the punycode functions are used.
1
1 /* example2.c --- Example code showing how to use punycode.
1 * Copyright (C) 2002-2016 Simon Josefsson
1 * Copyright (C) 2002 Adam M. Costello
1 *
1 * This file is part of GNU Libidn.
1 *
1 * This program is free software: you can redistribute it and/or modify
1 * it under the terms of the GNU General Public License as published by
1 * the Free Software Foundation, either version 3 of the License, or
1 * (at your option) any later version.
1 *
1 * This program is distributed in the hope that it will be useful,
1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1 * GNU General Public License for more details.
1 *
1 * You should have received a copy of the GNU General Public License
1 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1 *
1 */
1
1 #include <locale.h> /* setlocale() */
1
1 /*
1 * This file is derived from RFC 3492 written by Adam M. Costello.
1 *
1 * Disclaimer and license: Regarding this entire document or any
1 * portion of it (including the pseudocode and C code), the author
1 * makes no guarantees and is not responsible for any damage resulting
1 * from its use. The author grants irrevocable permission to anyone
1 * to use, modify, and distribute it in any way that does not diminish
1 * the rights of anyone else to use, modify, and distribute it,
1 * provided that redistributed derivative works do not contain
1 * misleading author or version information. Derivative works need
1 * not be licensed under similar terms.
1 *
1 */
1
1 #include <assert.h>
1 #include <stdio.h>
1 #include <stdlib.h>
1 #include <string.h>
1
1 #include <punycode.h>
1
1 /* For testing, we'll just set some compile-time limits rather than */
1 /* use malloc(), and set a compile-time option rather than using a */
1 /* command-line option. */
1
1 enum
1 {
1 unicode_max_length = 256,
1 ace_max_length = 256
1 };
1
1 static void
1 usage (char **argv)
1 {
1 fprintf (stderr,
1 "\n"
1 "%s -e reads code points and writes a Punycode string.\n"
1 "%s -d reads a Punycode string and writes code points.\n"
1 "\n"
1 "Input and output are plain text in the native character set.\n"
1 "Code points are in the form u+hex separated by whitespace.\n"
1 "Although the specification allows Punycode strings to contain\n"
1 "any characters from the ASCII repertoire, this test code\n"
1 "supports only the printable characters, and needs the Punycode\n"
1 "string to be followed by a newline.\n"
1 "The case of the u in u+hex is the force-to-uppercase flag.\n",
1 argv[0], argv[0]);
1 exit (EXIT_FAILURE);
1 }
1
1 static void
1 fail (const char *msg)
1 {
1 fputs (msg, stderr);
1 exit (EXIT_FAILURE);
1 }
1
1 static const char too_big[] =
1 "input or output is too large, recompile with larger limits\n";
1 static const char invalid_input[] = "invalid input\n";
1 static const char overflow[] = "arithmetic overflow\n";
1 static const char io_error[] = "I/O error\n";
1
1 /* The following string is used to convert printable */
1 /* characters between ASCII and the native charset: */
1
1 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 */
1 "ABCDEFGHIJKLMNO"
1 "PQRSTUVWXYZ[\\]^_" "`abcdefghijklmno" "pqrstuvwxyz{|}~\n";
1
1 int
1 main (int argc, char **argv)
1 {
1 enum punycode_status status;
1 int r;
1 size_t input_length, output_length, j;
1 unsigned char case_flags[unicode_max_length];
1
1 setlocale (LC_ALL, "");
1
1 if (argc != 2)
1 usage (argv);
1 if (argv[1][0] != '-')
1 usage (argv);
1 if (argv[1][2] != 0)
1 usage (argv);
1
1 if (argv[1][1] == 'e')
1 {
1 uint32_t input[unicode_max_length];
1 unsigned long codept;
1 char output[ace_max_length + 1], uplus[3];
1 int c;
1
1 /* Read the input code points: */
1
1 input_length = 0;
1
1 for (;;)
1 {
1 r = scanf ("%2s%lx", uplus, &codept);
1 if (ferror (stdin))
1 fail (io_error);
1 if (r == EOF || r == 0)
1 break;
1
1 if (r != 2 || uplus[1] != '+' || codept > (uint32_t) - 1)
1 {
1 fail (invalid_input);
1 }
1
1 if (input_length == unicode_max_length)
1 fail (too_big);
1
1 if (uplus[0] == 'u')
1 case_flags[input_length] = 0;
1 else if (uplus[0] == 'U')
1 case_flags[input_length] = 1;
1 else
1 fail (invalid_input);
1
1 input[input_length++] = codept;
1 }
1
1 /* Encode: */
1
1 output_length = ace_max_length;
1 status = punycode_encode (input_length, input, case_flags,
1 &output_length, output);
1 if (status == punycode_bad_input)
1 fail (invalid_input);
1 if (status == punycode_big_output)
1 fail (too_big);
1 if (status == punycode_overflow)
1 fail (overflow);
1 assert (status == punycode_success);
1
1 /* Convert to native charset and output: */
1
1 for (j = 0; j < output_length; ++j)
1 {
1 c = output[j];
1 assert (c >= 0 && c <= 127);
1 if (print_ascii[c] == 0)
1 fail (invalid_input);
1 output[j] = print_ascii[c];
1 }
1
1 output[j] = 0;
1 r = puts (output);
1 if (r == EOF)
1 fail (io_error);
1 return EXIT_SUCCESS;
1 }
1
1 if (argv[1][1] == 'd')
1 {
1 char input[ace_max_length + 2], *p, *pp;
1 uint32_t output[unicode_max_length];
1
1 /* Read the Punycode input string and convert to ASCII: */
1
1 if (!fgets (input, ace_max_length + 2, stdin))
1 fail (io_error);
1 if (ferror (stdin))
1 fail (io_error);
1 if (feof (stdin))
1 fail (invalid_input);
1 input_length = strlen (input) - 1;
1 if (input[input_length] != '\n')
1 fail (too_big);
1 input[input_length] = 0;
1
1 for (p = input; *p != 0; ++p)
1 {
1 pp = strchr (print_ascii, *p);
1 if (pp == 0)
1 fail (invalid_input);
1 *p = pp - print_ascii;
1 }
1
1 /* Decode: */
1
1 output_length = unicode_max_length;
1 status = punycode_decode (input_length, input, &output_length,
1 output, case_flags);
1 if (status == punycode_bad_input)
1 fail (invalid_input);
1 if (status == punycode_big_output)
1 fail (too_big);
1 if (status == punycode_overflow)
1 fail (overflow);
1 assert (status == punycode_success);
1
1 /* Output the result: */
1
1 for (j = 0; j < output_length; ++j)
1 {
1 r = printf ("%s+%04lX\n",
1 case_flags[j] ? "U" : "u", (unsigned long) output[j]);
1 if (r < 0)
1 fail (io_error);
1 }
1
1 return EXIT_SUCCESS;
1 }
1
1 usage (argv);
1 return EXIT_SUCCESS; /* not reached, but quiets compiler warning */
1 }
1