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