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