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