(root)/
fribidi-1.0.13/
bin/
fribidi-main.c
       1  /* FriBidi
       2   * fribidi-main.c - command line program for libfribidi
       3   *
       4   * Authors:
       5   *   Behdad Esfahbod, 2001, 2002, 2004
       6   *   Dov Grobgeld, 1999, 2000
       7   *
       8   * Copyright (C) 2004 Sharif FarsiWeb, Inc
       9   * Copyright (C) 2001,2002 Behdad Esfahbod
      10   * Copyright (C) 1999,2000 Dov Grobgeld
      11   * 
      12   * This library is free software; you can redistribute it and/or
      13   * modify it under the terms of the GNU Lesser General Public
      14   * License as published by the Free Software Foundation; either
      15   * version 2.1 of the License, or (at your option) any later version.
      16   * 
      17   * This library is distributed in the hope that it will be useful,
      18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20   * Lesser General Public License for more details.
      21   * 
      22   * You should have received a copy of the GNU Lesser General Public License
      23   * along with this library, in a file named COPYING; if not, write to the
      24   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      25   * Boston, MA 02110-1301, USA
      26   * 
      27   * For licensing issues, contact <fribidi.license@gmail.com>.
      28   */
      29  
      30  #include <common.h>
      31  
      32  #include <fribidi.h>
      33  #include <fribidi-deprecated.h>
      34  
      35  #include <stdio.h>
      36  
      37  #ifdef HAVE_CONFIG_H
      38  # include <config.h>
      39  #endif
      40  
      41  #ifdef STDC_HEADERS
      42  # include <stdlib.h>
      43  # include <stddef.h>
      44  #else
      45  # if HAVE_STDLIB_H
      46  #  include <stdlib.h>
      47  # endif
      48  #endif
      49  #ifdef HAVE_STRING_H
      50  # if STDC_HEADERS && HAVE_MEMORY_H
      51  # else
      52  #  include <memory.h>
      53  # endif
      54  # include <string.h>
      55  #endif
      56  #ifdef HAVE_STRINGS_H
      57  # include <strings.h>
      58  #endif
      59  
      60  #include "getopt.h"
      61  
      62  #define appname "fribidi"
      63  
      64  #define MAX_STR_LEN 65000
      65  
      66  
      67  #define ALLOCATE(tp,ln) ((tp *) fribidi_malloc (sizeof (tp) * (ln)))
      68  
      69  static void
      70  die2 (
      71    const char *fmt,
      72    const char *arg
      73  )
      74  {
      75    fprintf (stderr, "%s: ", appname);
      76    if (fmt)
      77      fprintf (stderr, fmt, arg);
      78    fprintf (stderr, "Try `%s --help' for more information.\n", appname);
      79    exit (-1);
      80  }
      81  
      82  #define die1(msg) die2("%s", msg)
      83  
      84  fribidi_boolean do_break, do_pad, do_mirror, do_reorder_nsm, do_clean;
      85  fribidi_boolean show_input, show_visual, show_basedir;
      86  fribidi_boolean show_ltov, show_vtol, show_levels;
      87  const int default_text_width = 80;
      88  int text_width;
      89  const char *char_set;
      90  const char *bol_text, *eol_text;
      91  FriBidiParType input_base_direction;
      92  int char_set_num;
      93  
      94  static void
      95  help (
      96    void
      97  )
      98  {
      99    /* Break help string into little ones, to assure ISO C89 conformance */
     100    printf ("Usage: " appname " [OPTION]... [FILE]...\n"
     101  	  "A command line interface for the " FRIBIDI_NAME " library.\n"
     102  	  "Convert a logical string to visual.\n"
     103  	  "\n"
     104  	  "  -h, --help            Display this information and exit\n"
     105  	  "  -V, --version         Display version information and exit\n"
     106  	  "  -v, --verbose         Verbose mode, same as --basedir --ltov --vtol\n"
     107  	  "                        --levels\n");
     108    printf ("  -d, --debug           Output debug information\n"
     109  	  "  -t, --test            Test " FRIBIDI_NAME
     110  	  ", same as --clean --nobreak\n"
     111  	  "                        --showinput --reordernsm --width %d\n",
     112  	  default_text_width);
     113    printf ("  -c, --charset CS      Specify character set, default is %s\n"
     114  	  "      --charsetdesc CS  Show descriptions for character set CS and exit\n"
     115  	  "      --caprtl          Old style: set character set to CapRTL\n",
     116  	  char_set);
     117    printf ("      --showinput       Output the input string too\n"
     118  	  "      --nopad           Do not right justify RTL lines\n"
     119  	  "      --nobreak         Do not break long lines\n"
     120  	  "  -w, --width W         Screen width for padding, default is %d, but if\n"
     121  	  "                        environment variable COLUMNS is defined, its value\n"
     122  	  "                        will be used, --width overrides both of them.\n",
     123  	  default_text_width);
     124    printf
     125      ("  -B, --bol BOL         Output string BOL before the visual string\n"
     126       "  -E, --eol EOL         Output string EOL after the visual string\n"
     127       "      --rtl             Force base direction to RTL\n"
     128       "      --ltr             Force base direction to LTR\n"
     129       "      --wrtl            Set base direction to RTL if no strong character found\n");
     130    printf
     131      ("      --wltr            Set base direction to LTR if no strong character found\n"
     132       "                        (default)\n"
     133       "      --nomirror        Turn mirroring off, to do it later\n"
     134       "      --reordernsm      Reorder NSM sequences to follow their base character\n"
     135       "      --clean           Remove explicit format codes in visual string\n"
     136       "                        output, currently does not affect other outputs\n"
     137       "      --basedir         Output Base Direction\n");
     138    printf ("      --ltov            Output Logical to Visual position map\n"
     139  	  "      --vtol            Output Visual to Logical position map\n"
     140  	  "      --levels          Output Embedding Levels\n"
     141  	  "      --novisual        Do not output the visual string, to be used with\n"
     142  	  "                        --basedir, --ltov, --vtol, --levels\n");
     143    printf ("  All string indexes are zero based\n" "\n" "Output:\n"
     144  	  "  For each line of input, output something like this:\n"
     145  	  "    [input-str` => '][BOL][[padding space]visual-str][EOL]\n"
     146  	  "    [\\n base-dir][\\n ltov-map][\\n vtol-map][\\n levels]\n");
     147  
     148    {
     149      int i;
     150      printf ("\n" "Available character sets:\n");
     151      for (i = 1; i <= FRIBIDI_CHAR_SETS_NUM; i++)
     152        printf ("  * %-10s: %-25s%1s\n",
     153  	      fribidi_char_set_name (i), fribidi_char_set_title (i),
     154  	      (fribidi_char_set_desc (i) ? "X" : ""));
     155      printf
     156        ("  X: Character set has descriptions, use --charsetdesc to see\n");
     157    }
     158  
     159    printf ("\nReport bugs online at\n<" FRIBIDI_BUGREPORT ">.\n");
     160    exit (0);
     161  }
     162  
     163  static void
     164  version (
     165    void
     166  )
     167  {
     168    printf (appname " %s", fribidi_version_info);
     169    exit (0);
     170  }
     171  
     172  static char *
     173  my_fribidi_strdup (
     174    char *s
     175  )
     176  {
     177    char *m;
     178  
     179    m = fribidi_malloc (strlen (s) + 1);
     180    if (!m)
     181      return NULL;
     182  
     183    strcpy (m, s);
     184  
     185    return m;
     186  }
     187  
     188  int
     189  main (
     190    int argc,
     191    char *argv[]
     192  )
     193  {
     194    int exit_val;
     195    fribidi_boolean file_found;
     196    char *s;
     197    FILE *IN;
     198  
     199    text_width = default_text_width;
     200    do_break = true;
     201    do_pad = true;
     202    do_mirror = true;
     203    do_clean = false;
     204    do_reorder_nsm = false;
     205    show_input = false;
     206    show_visual = true;
     207    show_basedir = false;
     208    show_ltov = false;
     209    show_vtol = false;
     210    show_levels = false;
     211    char_set = "UTF-8";
     212    bol_text = NULL;
     213    eol_text = NULL;
     214    input_base_direction = FRIBIDI_PAR_ON;
     215  
     216    if ((s = (char *) getenv ("COLUMNS")))
     217      {
     218        int i;
     219  
     220        i = atoi (s);
     221        if (i > 0)
     222  	text_width = i;
     223      }
     224  
     225  #define CHARSETDESC 257
     226  #define CAPRTL 258
     227  
     228    /* Parse the command line with getopt library */
     229    /* Must set argv[0], getopt uses it to generate error messages */
     230    argv[0] = appname;
     231    while (1)
     232      {
     233        int option_index = 0, c;
     234        static struct option long_options[] = {
     235  	{"help", 0, 0, 'h'},
     236  	{"version", 0, 0, 'V'},
     237  	{"verbose", 0, 0, 'v'},
     238  	{"debug", 0, 0, 'd'},
     239  	{"test", 0, 0, 't'},
     240  	{"charset", 1, 0, 'c'},
     241  	{"charsetdesc", 1, 0, CHARSETDESC},
     242  	{"caprtl", 0, 0, CAPRTL},
     243  	{"showinput", 0, (int *) (void *) &show_input, true},
     244  	{"nopad", 0, (int *) (void *) &do_pad, false},
     245  	{"nobreak", 0, (int *) (void *) &do_break, false},
     246  	{"width", 1, 0, 'w'},
     247  	{"bol", 1, 0, 'B'},
     248  	{"eol", 1, 0, 'E'},
     249  	{"nomirror", 0, (int *) (void *) &do_mirror, false},
     250  	{"reordernsm", 0, (int *) (void *) &do_reorder_nsm, true},
     251  	{"clean", 0, (int *) (void *) &do_clean, true},
     252  	{"ltr", 0, (int *) (void *) &input_base_direction, FRIBIDI_PAR_LTR},
     253  	{"rtl", 0, (int *) (void *) &input_base_direction, FRIBIDI_PAR_RTL},
     254  	{"wltr", 0, (int *) (void *) &input_base_direction,
     255  	 FRIBIDI_PAR_WLTR},
     256  	{"wrtl", 0, (int *) (void *) &input_base_direction,
     257  	 FRIBIDI_PAR_WRTL},
     258  	{"basedir", 0, (int *) (void *) &show_basedir, true},
     259  	{"ltov", 0, (int *) (void *) &show_ltov, true},
     260  	{"vtol", 0, (int *) (void *) &show_vtol, true},
     261  	{"levels", 0, (int *) (void *) &show_levels, true},
     262  	{"novisual", 0, (int *) (void *) &show_visual, false},
     263  	{0, 0, 0, 0}
     264        };
     265  
     266        c =
     267  	getopt_long (argc, argv, "hVvdtc:w:B:E:", long_options,
     268  		     &option_index);
     269        if (c == -1)
     270  	break;
     271  
     272        switch (c)
     273  	{
     274  	case 0:
     275  	  break;
     276  	case 'h':
     277  	  help ();
     278  	  break;
     279  	case 'V':
     280  	  version ();
     281  	  break;
     282  	case 'v':
     283  	  show_basedir = show_ltov = show_vtol = show_levels = true;
     284  	  break;
     285  	case 'w':
     286  	  text_width = atoi (optarg);
     287  	  if (text_width <= 0)
     288  	    die2 ("invalid screen width `%s'\n", optarg);
     289  	  break;
     290  	case 'B':
     291  	  bol_text = optarg;
     292  	  break;
     293  	case 'E':
     294  	  eol_text = optarg;
     295  	  break;
     296  	case 'd':
     297  	  if (!fribidi_set_debug (true))
     298  	    die1
     299  	      ("lib" FRIBIDI
     300  	       " must be compiled with DEBUG option to enable\nturn debug info on.\n");
     301  	  break;
     302  	case 't':
     303  	  do_clean = show_input = do_reorder_nsm = true;
     304  	  do_break = false;
     305  	  text_width = default_text_width;
     306  	  break;
     307  	case 'c':
     308  	  char_set = my_fribidi_strdup (optarg);
     309  	  if (!char_set)
     310  	    die1 ("memory allocation failed for char_set!");
     311  	  break;
     312  	case CAPRTL:
     313  	  char_set = "CapRTL";
     314  	  break;
     315  	case CHARSETDESC:
     316  	  char_set = optarg;
     317  	  char_set_num = fribidi_parse_charset (char_set);
     318  	  if (!char_set_num)
     319  	    die2 ("unrecognized character set `%s'\n", char_set);
     320  	  if (!fribidi_char_set_desc (char_set_num))
     321  	    die2 ("no description available for character set `%s'\n",
     322  		  fribidi_char_set_name (char_set_num));
     323  	  else
     324  	    printf ("Descriptions for character set %s:\n"
     325  		    "\n" "%s", fribidi_char_set_title (char_set_num),
     326  		    fribidi_char_set_desc (char_set_num));
     327  	  exit (0);
     328  	  break;
     329  	case ':':
     330  	case '?':
     331  	  die2 (NULL, NULL);
     332  	  break;
     333  	default:
     334  	  break;
     335  	}
     336      }
     337  
     338    char_set_num = fribidi_parse_charset (char_set);
     339  
     340    if (!char_set_num)
     341      die2 ("unrecognized character set `%s'\n", char_set);
     342  
     343  FRIBIDI_BEGIN_IGNORE_DEPRECATIONS
     344    fribidi_set_mirroring (do_mirror);
     345    fribidi_set_reorder_nsm (do_reorder_nsm);
     346  FRIBIDI_END_IGNORE_DEPRECATIONS
     347    exit_val = 0;
     348    file_found = false;
     349    while (optind < argc || !file_found)
     350      {
     351        const char *filename;
     352  
     353        filename = optind < argc ? argv[optind++] : "-";
     354        file_found = true;
     355  
     356        /* Open the infile for reading */
     357        if (filename[0] == '-' && !filename[1])
     358  	{
     359  	  IN = stdin;
     360  	}
     361        else
     362  	{
     363  	  IN = fopen (filename, "r");
     364  	  if (!IN)
     365  	    {
     366  	      fprintf (stderr, "%s: %s: no such file or directory\n",
     367  		       appname, filename);
     368  	      exit_val = 1;
     369  	      continue;
     370  	    }
     371  	}
     372  
     373        /* Read and process input one line at a time */
     374        {
     375  	char S_[MAX_STR_LEN];
     376  	int padding_width, break_width;
     377  
     378  	padding_width = show_input ? (text_width - 10) / 2 : text_width;
     379  	break_width = do_break ? padding_width : 3 * MAX_STR_LEN;
     380  
     381  	while (fgets (S_, sizeof (S_) - 1, IN))
     382  	  {
     383  	    const char *new_line, *nl_found;
     384  	    FriBidiChar logical[MAX_STR_LEN];
     385  	    char outstring[MAX_STR_LEN];
     386  	    FriBidiParType base;
     387  	    FriBidiStrIndex len;
     388  
     389  	    nl_found = "";
     390  	    S_[sizeof (S_) - 1] = 0;
     391  	    len = strlen (S_);
     392  	    /* chop */
     393  	    if (len > 0 && S_[len - 1] == '\n')
     394  	      {
     395  		len--;
     396  		S_[len] = '\0';
     397  		new_line = "\n";
     398  	      }
     399  	    else
     400  	      new_line = "";
     401  	    /* TODO: handle \r */
     402  
     403  	    len = fribidi_charset_to_unicode (char_set_num, S_, len, logical);
     404  
     405  	    {
     406  	      FriBidiChar *visual;
     407  	      FriBidiStrIndex *ltov, *vtol;
     408  	      FriBidiLevel *levels;
     409  	      fribidi_boolean log2vis;
     410  
     411  	      visual = show_visual ? ALLOCATE (FriBidiChar,
     412  					       len + 1
     413  	      ) : NULL;
     414  	      ltov = show_ltov ? ALLOCATE (FriBidiStrIndex,
     415  					   len + 1
     416  	      ) : NULL;
     417  	      vtol = show_vtol ? ALLOCATE (FriBidiStrIndex,
     418  					   len + 1
     419  	      ) : NULL;
     420  	      levels = show_levels ? ALLOCATE (FriBidiLevel,
     421  					       len + 1
     422  	      ) : NULL;
     423  
     424  	      /* Create a bidi string. */
     425  	      base = input_base_direction;
     426  
     427  	      log2vis = fribidi_log2vis (logical, len, &base,
     428  					 /* output */
     429  					 visual, ltov, vtol, levels);
     430  
     431  	      if (log2vis)
     432  		{
     433  
     434  		  if (show_input)
     435  		    printf ("%-*s => ", padding_width, S_);
     436  
     437  		  /* Remove explicit marks, if asked for. */
     438  
     439  		  if (do_clean)
     440  		    len =
     441  		      fribidi_remove_bidi_marks (visual, len, ltov, vtol,
     442  						 levels);
     443  
     444  		  if (show_visual)
     445  		    {
     446  		      printf ("%s", nl_found);
     447  
     448  		      if (bol_text)
     449  			printf ("%s", bol_text);
     450  
     451  		      /* Convert it to input charset and print. */
     452  		      {
     453  			FriBidiStrIndex idx, st;
     454  			for (idx = 0; idx < len;)
     455  			  {
     456  			    FriBidiStrIndex wid, inlen;
     457  
     458  			    wid = break_width;
     459  			    st = idx;
     460  			    if (char_set_num != FRIBIDI_CHAR_SET_CAP_RTL)
     461  			      while (wid > 0 && idx < len)
     462  				{
     463  				  wid -=
     464  				    FRIBIDI_IS_EXPLICIT_OR_ISOLATE_OR_BN_OR_NSM
     465  				    (fribidi_get_bidi_type (visual[idx])) ? 0
     466  				    : 1;
     467  				  idx++;
     468  				}
     469  			    else
     470  			      while (wid > 0 && idx < len)
     471  				{
     472  				  wid--;
     473  				  idx++;
     474  				}
     475  			    if (wid < 0 && idx - st > 1)
     476  			      idx--;
     477  			    inlen = idx - st;
     478  
     479  			    fribidi_unicode_to_charset (char_set_num,
     480  							visual + st, inlen,
     481  							outstring);
     482  			    if (FRIBIDI_IS_RTL (base))
     483  			      printf ("%*s",
     484  				      (int) (do_pad ? (padding_width +
     485  						       strlen (outstring) -
     486  						       (break_width -
     487  							wid)) : 0),
     488  				      outstring);
     489  			    else
     490  			      printf ("%s", outstring);
     491  			    if (idx < len)
     492  			      printf ("\n");
     493  			  }
     494  		      }
     495  		      if (eol_text)
     496  			printf ("%s", eol_text);
     497  
     498  		      nl_found = "\n";
     499  		    }
     500  		  if (show_basedir)
     501  		    {
     502  		      printf ("%s", nl_found);
     503  		      printf ("Base direction: %s",
     504  			      (FRIBIDI_DIR_TO_LEVEL (base) ? "R" : "L"));
     505  		      nl_found = "\n";
     506  		    }
     507  		  if (show_ltov)
     508  		    {
     509  		      FriBidiStrIndex i;
     510  
     511  		      printf ("%s", nl_found);
     512  		      for (i = 0; i < len; i++)
     513  			printf ("%ld ", (long) ltov[i]);
     514  		      nl_found = "\n";
     515  		    }
     516  		  if (show_vtol)
     517  		    {
     518  		      FriBidiStrIndex i;
     519  
     520  		      printf ("%s", nl_found);
     521  		      for (i = 0; i < len; i++)
     522  			printf ("%ld ", (long) vtol[i]);
     523  		      nl_found = "\n";
     524  		    }
     525  		  if (show_levels)
     526  		    {
     527  		      FriBidiStrIndex i;
     528  
     529  		      printf ("%s", nl_found);
     530  		      for (i = 0; i < len; i++)
     531  			printf ("%d ", (int) levels[i]);
     532  		      nl_found = "\n";
     533  		    }
     534  		}
     535  	      else
     536  		{
     537  		  exit_val = 2;
     538  		}
     539  
     540  	      if (show_visual)
     541  		free (visual);
     542  	      if (show_ltov)
     543  		free (ltov);
     544  	      if (show_vtol)
     545  		free (vtol);
     546  	      if (show_levels)
     547  		free (levels);
     548  	    }
     549  
     550  	    if (*nl_found)
     551  	      printf ("%s", new_line);
     552  	  }
     553        }
     554      }
     555  
     556    return exit_val;
     557  }
     558  
     559  /* Editor directions:
     560   * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
     561   */