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
69static void
70die2 (
71 const char *fmt,
72 const char *arg
73)
74{
75 fprintf (stderr, format: "%s: ", appname);
76 if (fmt)
77 fprintf (stderr, format: fmt, arg);
78 fprintf (stderr, format: "Try `%s --help' for more information.\n", appname);
79 exit (status: -1);
80}
81
82#define die1(msg) die2("%s", msg)
83
84fribidi_boolean do_break, do_pad, do_mirror, do_reorder_nsm, do_clean;
85fribidi_boolean show_input, show_visual, show_basedir;
86fribidi_boolean show_ltov, show_vtol, show_levels;
87const int default_text_width = 80;
88int text_width;
89const char *char_set;
90const char *bol_text, *eol_text;
91FriBidiParType input_base_direction;
92int char_set_num;
93
94static void
95help (
96 void
97)
98{
99 /* Break help string into little ones, to assure ISO C89 conformance */
100 printf (format: "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 (format: " -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 (format: " -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 (format: " --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 (format: " -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 (format: " --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 (format: " --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 (format: " 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 (format: "\n" "Available character sets:\n");
151 for (i = 1; i <= FRIBIDI_CHAR_SETS_NUM; i++)
152 printf (format: " * %-10s: %-25s%1s\n",
153 fribidi_char_set_name (char_set: i), fribidi_char_set_title (char_set: i),
154 (fribidi_char_set_desc (char_set: i) ? "X" : ""));
155 printf
156 (format: " X: Character set has descriptions, use --charsetdesc to see\n");
157 }
158
159 printf (format: "\nReport bugs online at\n<" FRIBIDI_BUGREPORT ">.\n");
160 exit (status: 0);
161}
162
163static void
164version (
165 void
166)
167{
168 printf (appname " %s", fribidi_version_info);
169 exit (status: 0);
170}
171
172static char *
173my_fribidi_strdup (
174 char *s
175)
176{
177 char *m;
178
179 m = fribidi_malloc (size: strlen (s: s) + 1);
180 if (!m)
181 return NULL;
182
183 strcpy (dest: m, src: s);
184
185 return m;
186}
187
188int
189main (
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 (name: "COLUMNS")))
217 {
218 int i;
219
220 i = atoi (nptr: 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: argc, argv: argv, shortopts: "hVvdtc:w:B:E:", longopts: long_options,
268 longind: &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 (nptr: optarg);
287 if (text_width <= 0)
288 die2 (fmt: "invalid screen width `%s'\n", arg: 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 (s: 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 (s: char_set);
318 if (!char_set_num)
319 die2 (fmt: "unrecognized character set `%s'\n", arg: char_set);
320 if (!fribidi_char_set_desc (char_set: char_set_num))
321 die2 (fmt: "no description available for character set `%s'\n",
322 arg: fribidi_char_set_name (char_set: char_set_num));
323 else
324 printf (format: "Descriptions for character set %s:\n"
325 "\n" "%s", fribidi_char_set_title (char_set: char_set_num),
326 fribidi_char_set_desc (char_set: char_set_num));
327 exit (status: 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 (s: char_set);
339
340 if (!char_set_num)
341 die2 (fmt: "unrecognized character set `%s'\n", arg: char_set);
342
343FRIBIDI_BEGIN_IGNORE_DEPRECATIONS
344 fribidi_set_mirroring (state: do_mirror);
345 fribidi_set_reorder_nsm (state: do_reorder_nsm);
346FRIBIDI_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: filename, modes: "r");
364 if (!IN)
365 {
366 fprintf (stderr, format: "%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: S_, n: sizeof (S_) - 1, stream: 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: 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: char_set_num, s: S_, len, us: 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 (str: logical, len, pbase_dir: &base,
428 /* output */
429 visual_str: visual, positions_L_to_V: ltov, positions_V_to_L: vtol, embedding_levels: levels);
430
431 if (log2vis)
432 {
433
434 if (show_input)
435 printf (format: "%-*s => ", padding_width, S_);
436
437 /* Remove explicit marks, if asked for. */
438
439 if (do_clean)
440 len =
441 fribidi_remove_bidi_marks (str: visual, len, positions_to_this: ltov, position_from_this_list: vtol,
442 embedding_levels: levels);
443
444 if (show_visual)
445 {
446 printf (format: "%s", nl_found);
447
448 if (bol_text)
449 printf (format: "%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: char_set_num,
480 us: visual + st, len: inlen,
481 s: outstring);
482 if (FRIBIDI_IS_RTL (base))
483 printf (format: "%*s",
484 (int) (do_pad ? (padding_width +
485 strlen (s: outstring) -
486 (break_width -
487 wid)) : 0),
488 outstring);
489 else
490 printf (format: "%s", outstring);
491 if (idx < len)
492 printf (format: "\n");
493 }
494 }
495 if (eol_text)
496 printf (format: "%s", eol_text);
497
498 nl_found = "\n";
499 }
500 if (show_basedir)
501 {
502 printf (format: "%s", nl_found);
503 printf (format: "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 (format: "%s", nl_found);
512 for (i = 0; i < len; i++)
513 printf (format: "%ld ", (long) ltov[i]);
514 nl_found = "\n";
515 }
516 if (show_vtol)
517 {
518 FriBidiStrIndex i;
519
520 printf (format: "%s", nl_found);
521 for (i = 0; i < len; i++)
522 printf (format: "%ld ", (long) vtol[i]);
523 nl_found = "\n";
524 }
525 if (show_levels)
526 {
527 FriBidiStrIndex i;
528
529 printf (format: "%s", nl_found);
530 for (i = 0; i < len; i++)
531 printf (format: "%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 (ptr: visual);
542 if (show_ltov)
543 free (ptr: ltov);
544 if (show_vtol)
545 free (ptr: vtol);
546 if (show_levels)
547 free (ptr: levels);
548 }
549
550 if (*nl_found)
551 printf (format: "%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 */
562

source code of gtk/subprojects/fribidi/bin/fribidi-main.c