/rusxmms/rcctools

To get this branch, use:
bzr branch http://suren.me/webbzr/rusxmms/rcctools
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
1
/*
2
  rcc_recode - command line interface to LibRCC
3
5 by Suren A. Chilingaryan
Fix e-mail in copyright statement
4
  Copyright (C) 2005-2018 Suren A. Chilingaryan <csa@suren.me>
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
5
6
  This program is free software; you can redistribute it and/or modify it
7
  under the terms of version 2 of the GNU General Public License as published
8
  by the Free Software Foundation.
9
10
  This program is distributed in the hope that it will be useful, but WITHOUT
11
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13
  more details.
14
15
  You should have received a copy of the GNU General Public License along
16
  with this program; if not, write to the Free Software Foundation, Inc.,
4 by Suren A. Chilingaryan
FSF address updated
17
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
18
*/
19
1 by Suren A. Chilingaryan
initial import
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <unistd.h>
23
#include <string.h>
24
#include <locale.h>
25
26
#include <errno.h>
27
28
#include "config.h"
29
30
#ifdef HAVE_SYS_STAT_H
31
# include <sys/stat.h>
32
#endif /* HAVE_SYS_STAT_H */
33
#ifdef HAVE_SYS_FILE_H
34
# include <sys/file.h>
35
#endif /* HAVE_SYS_FILE_H */
36
#ifdef HAVE_SYS_TYPES_H
37
# include <sys/types.h>
38
#endif /* HAVE_SYS_TYPES_H */
39
#ifdef HAVE_DIRENT_H
40
# include <dirent.h>
41
#endif /* HAVE_DIRENT_H */
42
43
#ifdef HAVE_GETOPT_H
44
# include <getopt.h>
45
#endif /* HAVE_GETOPT_H */
46
47
#include <librcc.h>
48
49
#ifndef RCC_OPTION_TRANSLATE_SKIP_PARENT
50
# define RCC_OPTION_TRANSLATE_SKIP_PARENT RCC_OPTION_TRANSLATE_SKIP_PARRENT
51
#endif
52
53
typedef enum {
54
    MODE_STDIN = 0x1000,
55
    MODE_DIRECTORY,
56
    MODE_FILE,
57
    MODE_FILELIST
58
} Modes;
59
60
int mode = MODE_STDIN;
61
62
typedef enum {
63
    OPT_CONFIG = 'c',
64
    OPT_ENCODING_IN = 'e',
65
    OPT_FROM = 'f',
66
    OPT_HELP = 'h',
67
    OPT_LANGUAGE_IN = 'l',
68
    OPT_TO = 't',
69
    OPT_YES = 'y',
70
    OPT_ENCODING_OUT,
71
    OPT_LANGUAGE_OUT,
72
    OPT_TRANSLATION,
73
    OPT_CACHING,
74
    OPT_CACHE,
75
    OPT_AUTODETECT,
76
    OPT_OFFLINE,
77
    OPT_TIMEOUT,
78
    OPT_SUBDIRS,
79
} Options;
80
81
static struct option long_options[] = {
82
    {"config",			required_argument, 0, OPT_CONFIG },
83
    {"from", 			required_argument, 0, OPT_FROM }, 
84
    {"to", 			required_argument, 0, OPT_TO },
85
    {"force-encoding",		required_argument, 0, OPT_ENCODING_IN },
86
    {"force-language", 		required_argument, 0, OPT_LANGUAGE_IN },
87
    {"force-target-encoding",	required_argument, 0, OPT_ENCODING_OUT },
88
    {"force-target-language",	required_argument, 0, OPT_LANGUAGE_OUT },
89
    {"language-detection",	required_argument, 0, OPT_AUTODETECT },
90
    {"translation",		optional_argument, 0, OPT_TRANSLATION },
91
    {"caching",			optional_argument, 0, OPT_CACHING },
92
    {"cache",			required_argument, 0, OPT_CACHE },
93
    {"timeout",			required_argument, 0, OPT_TIMEOUT },
94
    {"force",			no_argument, 0, OPT_YES },
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
95
#ifdef RCC_OPTION_OFFLINE
1 by Suren A. Chilingaryan
initial import
96
    {"allow-offline-processing",no_argument, 0, OPT_OFFLINE },
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
97
#endif /* RCC_OPTION_OFFLINE */
1 by Suren A. Chilingaryan
initial import
98
    {"disable-subdirs",		no_argument, 0, OPT_SUBDIRS },
99
    {"stdin",			no_argument, &mode, MODE_STDIN },
100
    {"directory", 		no_argument, &mode, MODE_DIRECTORY },
101
    {"file",			no_argument, &mode, MODE_FILE },
102
    {"filelist",		no_argument, &mode, MODE_FILELIST },
103
    {"help",			no_argument, 0, OPT_HELP },
104
    { 0, 0, 0, 0 }
105
};
106
107
void Usage(int argc, char *argv[]) {
108
    printf(
109
"Usage:\n"
110
" %s [options] [mode] [file|directory]\n"
111
"  Modes:\n"
112
"	--stdin		- Convert stdin to stdout\n"
113
"	--directory	- Convert file names in specified directory\n"
114
"	--file		- Convert specified file\n"
115
"	--filelist	- Convert all files writed on stdin\n"
116
"	--help		- Help message\n"
117
"\n"
118
"  Options:\n"
119
"	-c <config>	- Specify configuration name\n"
120
"	-f <class>	- Source class ('in' is default)\n"
121
"	-t <class>	- Output class ('out' is default)\n"
122
"	-e <enc>	- Force specified source encoding (autodetection)\n"
123
"	-l <lang>	- Force specified source language (from LC_CTYPE)\n"
124
"	--force-target-encoding=<enc>\n"
125
"			- Convert to the specified encoding\n"
126
"	--force-target-language=<enc>\n"
127
"			- Translate to the specified language\n"
128
"	--caching=[mode]\n"
129
"			- Use recodings cache. Following modes are supported\n"
130
"			off 		- Turn off\n"
131
"			use		- Use cached values (default)\n"
132
"			add		- Add new recodings to cache\n"
133
"			replace		- Replace encodings in cache\n"
134
"	--cache=<name>\n"
135
"			- Use specified cache database instead of default one\n"
136
"	--translation=[mode]\n"
137
"			- Enable translation. Following modes are supported:\n"
138
"			full		- Full\n"
139
"			skip_parent	- Skip translation to parent lang\n"
140
"			skip_related	- Skip translation between related langs\n"
141
"			english		- Translate to english (default)\n"
142
"			transliterate	- Transliterate\n"
143
"	--language-detection=[mode]\n"
144
"			- Lanuage autodetection. Following modes are supported:\n"
145
"			off		- Current language is considered\n"
146
"			on		- Use only configured langs (default)\n"
147
"			all		- Try everything (slow)\n"
148
"	--timeout=<us>\n"
149
"			- Specify recoding timeout in microseconds (1s default)\n"
150
"\n"
151
"	-y		- Do not ask any question\n"
152
"	--disable-subdirs\n"
153
"			- Do not descend into the sub directories\n"
154
"\n"
155
" Language Relations:\n"
156
"  To prevent unneccesary translations the concept of related/parent languages is\n"
157
"  introduced. For each language you can specify a parent language.\n"
158
"  skip_parent   translation option will turn off translation to parent language\n"
159
"  skip_related  translation option will additionaly turn off translation from\n"
160
"  parent language.\n"
161
"\n"
162
"  For example, in the default configuration Russian is parent of Ukrainian, and\n"
163
"  English is parent of all other languages. With \"skip_parrent\" option the\n"
164
"  translation from Russian to Ukrainian would be turned off, but translation\n"
165
"  from Ukrainian to Russian would operate. With \"skip_related\" option the\n"
166
"  translation in both directions would be disabled\n"
167
"\n\n"
168
" Language Detection:\n"
169
"  Current version uses aspell dictionaries to autodetect language. Therefore,\n"
170
"  only languages with aspell available in the system aspell dictionaries are\n"
171
"  autodected. Beware, if your system contains a lot of installed languages,\n"
172
"  the autodection may take considerable amount of time.\n"
173
"\n\n",
174
argv[0]);
175
}
176
177
/*
178
    fs: is a standard class here, we do not need fs detecting here
179
*/
180
static rcc_class classes[] = {
181
    { "unicode", RCC_CLASS_TRANSLATE_CURRENT, "UTF-8", NULL, "Dummy", 0 },
182
    { "in", RCC_CLASS_STANDARD, NULL, NULL, "Input Encoding", 0 },
183
    { "out", RCC_CLASS_TRANSLATE_CURRENT, "LC_CTYPE", NULL, "Output Encoding", 0 },
184
    { "id3", RCC_CLASS_STANDARD, "in", NULL, "ID3 Encoding", 0 },
185
    { "id3v2", RCC_CLASS_STANDARD, "id3", NULL, "ID3 v.2 Encoding", 0},
186
    { "pl", RCC_CLASS_STANDARD, "id3", NULL, "PlayList Title Encoding", 0},
187
    { "plfs", RCC_CLASS_STANDARD, "pl", NULL, "PlayList File Encoding", 0 },
188
    { "fs", RCC_CLASS_STANDARD, "LC_CTYPE", NULL, "FileSystem Encoding", 0 },
189
    { "oem", RCC_CLASS_STANDARD, "in", NULL, "Zip OEM Encoding", 0 },
190
    { "iso", RCC_CLASS_STANDARD, "in", NULL, "Zip ISO Encoding", 0 },
191
    { "ftp", RCC_CLASS_STANDARD, "in", NULL, "FTP Encoding", 0 },
192
    { NULL }
193
};
194
195
rcc_class_id GetClass(const char *name) {
196
    int i;
197
    
198
    for (i = 1; classes[i].name; i++) {
199
	if ((!strcasecmp(name, classes[i].name))||(!strcasecmp(name, classes[i].fullname)))
200
	    return i;
201
    }
202
    return (rcc_class_id)-1;
203
}
204
205
static char ask = 1;
206
static char process_subdirs = 1;
207
static rcc_language_id source_language_id, target_language_id;
208
static rcc_class_id source_class_id = 1, target_class_id = 2;
209
static char *efrom = NULL, *eto = NULL;
210
211
static int translate = RCC_OPTION_TRANSLATE_OFF;
212
213
214
char *Translate(const char *source);
215
int Stdin(const char *arg);
216
int Directory(const char *arg);
217
218
int main(int argc, char *argv[]) {
219
    rcc_language_id language_id, current_language_id, english_language_id;
220
    
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
221
    unsigned char c;
1 by Suren A. Chilingaryan
initial import
222
    
223
    char *arg = NULL;
224
    
225
    char *config_name = NULL;
226
    char *cache_name = NULL;
227
    
228
    char *from = "in";
229
    char *to = "out";
230
    
231
    unsigned char from_forced = 0;
232
    unsigned char to_forced = 0;
233
    
234
    char *lfrom = NULL;
235
    char *lto = NULL;
236
    
237
    int cache = RCC_OPTION_LEARNING_FLAG_USE;
238
    
239
    int ldetect = 0;
240
    int ldetect_all = 0;
241
    int ldetect_force = 0;
242
243
    unsigned long timeout = 0;
244
    char offline = 0;
245
    
246
    int option_index = 0;
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
247
    while ((c = getopt_long(argc, argv, "yhe:f:l:t:c:", long_options, &option_index)) != (unsigned char)-1) {
1 by Suren A. Chilingaryan
initial import
248
	switch (c) {
249
	    case 0:
250
	    break;
251
	    case OPT_HELP:
252
		Usage(argc, argv);
253
		exit(0);		
254
	    break;
255
	    case OPT_CONFIG:
256
		config_name = optarg;
257
	    break;
258
	    case OPT_CACHE:
259
		cache_name = optarg;
260
	    case OPT_FROM:
261
		from_forced = 1;
262
		from = optarg;
263
	    break;
264
	    case OPT_TO:
265
		to_forced = 1;
266
		to = optarg;
267
	    break;
268
	    case OPT_ENCODING_IN:
269
		efrom = optarg;
270
	    break;
271
	    case OPT_ENCODING_OUT:
272
		eto = optarg;
273
	    break;
274
	    case OPT_LANGUAGE_IN:
275
		lfrom = optarg;
276
/*
277
		Selects main language, but for translation we can switch on
278
		autodetection. Should do it manualy.
279
*/		
280
		if (!ldetect_force) {
281
		    ldetect = 0;
282
		    ldetect_force = 1;
283
		}
284
285
	    break;
286
	    case OPT_LANGUAGE_OUT:
287
		lto = optarg;
288
	    break;
289
	    case OPT_TRANSLATION:
290
		if (!optarg)
291
		    translate = RCC_OPTION_TRANSLATE_TO_ENGLISH;
292
		else if (!strcasecmp(optarg, "full"))
293
		    translate = RCC_OPTION_TRANSLATE_FULL;
294
		else if (!strcasecmp(optarg, "skip_parent"))
295
		    translate = RCC_OPTION_TRANSLATE_SKIP_PARENT;
296
		else if (!strcasecmp(optarg, "skip_related"))
297
		    translate = RCC_OPTION_TRANSLATE_SKIP_RELATED;
298
		else if (!strcasecmp(optarg, "english"))
299
		    translate = RCC_OPTION_TRANSLATE_TO_ENGLISH;
300
		else if (!strcasecmp(optarg, "transliterate"))
301
		    translate = RCC_OPTION_TRANSLATE_TRANSLITERATE;
302
		else if (!strcasecmp(optarg, "off"))
303
		    translate = RCC_OPTION_TRANSLATE_OFF;
304
		else {
305
		    fprintf(stderr, "*** Unknown translation mode: %s\n\n", optarg);
306
		    Usage(argc, argv);
307
		    exit(0);
308
		}
309
		
310
		if (!ldetect_force) {
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
311
		    if ((optarg)&&(!strcasecmp(optarg, "off")))
1 by Suren A. Chilingaryan
initial import
312
			ldetect = 0;
313
		    else 
314
			ldetect = 1;
315
		}
316
	    break;
317
	    case OPT_CACHING:
318
	    	if (!optarg)
319
		    cache = RCC_OPTION_LEARNING_FLAG_USE;
320
		else if (!strcasecmp(optarg, "off"))
321
		    cache = 0;
322
		else if (!strcasecmp(optarg, "use"))
323
		    cache = RCC_OPTION_LEARNING_FLAG_USE;
324
		else if (!strcasecmp(optarg, "add"))
325
		    cache = RCC_OPTION_LEARNING_FLAG_USE|RCC_OPTION_LEARNING_FLAG_LEARN;
326
		else if (!strcasecmp(optarg, "replace"))
327
		    cache = RCC_OPTION_LEARNING_FLAG_LEARN;
328
		else {
329
		    fprintf(stderr, "*** Unknown caching mode: %s\n\n", optarg);
330
		    Usage(argc, argv);
331
		    exit(0);
332
		}
333
	    break;
334
	    case OPT_AUTODETECT:
335
		ldetect_force = 1;
336
337
		if (!optarg) ldetect = 1;
338
		else if (!strcasecmp(optarg, "off")) {
339
		    ldetect = 0;
340
		    ldetect_force = 1;
341
		} else if (!strcasecmp(optarg, "on")) {
342
		    ldetect = 1;
343
		    ldetect_all = 0;
344
		    ldetect_force = 1;
345
		} else if (!strcasecmp(optarg, "all")) {
346
		    ldetect = 1;
347
		    ldetect_all = 1;
348
		    ldetect_force = 1;
349
		}
350
	    break;
351
	    case OPT_TIMEOUT:
352
		timeout = atoi(optarg);
353
	    break;
354
	    case OPT_OFFLINE:
355
		offline = 1;
356
	    break;
357
	    case OPT_SUBDIRS:
358
		process_subdirs = 0;
359
	    break;
360
	    case OPT_YES:
361
		ask = 0;
362
	    break;
363
	    default:
364
		Usage(argc, argv);
365
		exit(0);
366
	}
367
    }
368
    
369
    if (optind < argc) {
370
	if ((optind + 1) < argc) {
371
	    fprintf(stderr, "*** Invalid non-option arguments:\n");
372
	    for (;optind < argc;optind++) {
373
		puts(argv[optind]);
374
	    }
375
	    fprintf(stderr, "\n\n");
376
	    Usage(argc,argv);
377
	    exit(0);
378
	}
379
	arg = argv[optind];
380
    }
381
382
    switch (mode) {
383
	case MODE_DIRECTORY:
384
	    if (!from_forced) from = "fs";
385
	    if (!to_forced) to = "fs";
386
	break;
387
	default:
388
	    ;
389
    }
390
	
391
    setlocale(LC_ALL, "");
392
    
393
394
    rccInit();
395
    rccInitDefaultContext(NULL, 0, 0, classes, 0);
396
    rccInitDb4(NULL, cache_name, 0);
397
398
    if (timeout) rccSetOption(NULL, RCC_OPTION_TIMEOUT, timeout);
399
400
    if (config_name) rccLoad(NULL, config_name);
401
402
403
    rccSetOption(NULL, RCC_OPTION_LEARNING_MODE, cache);
404
405
    if (translate != RCC_OPTION_TRANSLATE_OFF) 
406
	rccSetOption(NULL, RCC_OPTION_TRANSLATE, translate);
407
408
    if (ldetect) {
409
	rccSetOption(NULL, RCC_OPTION_AUTODETECT_LANGUAGE, 1);
410
	if (ldetect_all) {
411
	    rccSetOption(NULL, RCC_OPTION_CONFIGURED_LANGUAGES_ONLY, 0);
412
	}
413
    }
414
    
415
	// DS: More checks, sometimes we can skip that.
416
    if ((lfrom)||(lto)) {
417
//	if (lfrom) rccSetOption(NULL, RCC_OPTION_AUTODETECT_LANGUAGE, 1);
418
	rccSetOption(NULL, RCC_OPTION_CONFIGURED_LANGUAGES_ONLY, 0);
419
    }
420
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
421
#ifdef RCC_OPTION_OFFLINE
1 by Suren A. Chilingaryan
initial import
422
    if (offline)
423
	rccSetOption(NULL, RCC_OPTION_OFFLINE, 1);
2 by Suren A. Chilingaryan
GPL disclaimer is added to source
424
#endif /* RCC_OPTION_OFFLINE */
1 by Suren A. Chilingaryan
initial import
425
426
    if (from) {
427
	source_class_id = GetClass(from);
428
	if (source_class_id == (rcc_class_id)-1) {
429
	    rccFree();
430
	    fprintf(stderr, "*** Invalid source class (%s) specified\n", from);
431
	    exit(1);
432
	}
433
    } 
434
    if (to) {
435
	target_class_id = GetClass(to);
436
	if (target_class_id == (rcc_class_id)-1) {
437
	    rccFree();
438
	    fprintf(stderr, "*** Invalid target class (%s) specified\n", to);
439
	    exit(1);
440
	}
441
    } 
442
    
443
    current_language_id = rccGetCurrentLanguage(NULL);
444
    english_language_id = rccGetLanguageByName(NULL, "en");
445
446
    if (lfrom) {
447
	source_language_id = rccGetLanguageByName(NULL, lfrom);
448
	if (source_language_id == (rcc_language_id)-1) {
449
	    rccFree();
450
	    fprintf(stderr, "*** Invalid source language (%s) specified\n", lfrom);
451
	    exit(1);
452
	}
453
    } else source_language_id = current_language_id;
454
    
455
    if (lto) {
456
	target_language_id = rccGetLanguageByName(NULL, lto);
457
	if (target_language_id == (rcc_language_id)-1) {
458
	    rccFree();
459
	    fprintf(stderr, "*** Invalid target language (%s) specified\n", lto);
460
	    exit(1);
461
	}
462
    } else target_language_id = current_language_id;
463
    
464
    if (source_language_id == target_language_id) {
465
	language_id = source_language_id;
466
	
467
	if (language_id != current_language_id) {
468
	    if ((rccSetLanguage(NULL, language_id))||(!rccGetCurrentLanguageName(NULL))) {
469
		rccFree();
470
		fprintf(stderr, "*** Unable to set the specified language (%s)\n", rccGetLanguageName(NULL, language_id));
471
		exit(1);
472
	    }
473
	} else {
474
	    // Automatic
475
	    if (!rccGetCurrentLanguageName(NULL)) {
476
		if (current_language_id != english_language_id) {
477
		    language_id = english_language_id;
478
		    rccSetLanguage(NULL, english_language_id);
479
		}
480
		
481
		if (!rccGetCurrentLanguageName(NULL)) {
482
		    rccFree();
483
		    fprintf(stderr, "*** Default language (%s) is not configured\n", rccGetLanguageName(NULL, current_language_id));
484
		    exit(1);
485
		}
486
	    }
487
	}
488
	
489
    } else {
490
	language_id = (rcc_language_id)-1;
491
	
492
	    // Checking if languages are selectable
493
	if ((rccSetLanguage(NULL, source_language_id))||(!rccGetCurrentLanguageName(NULL))) {
494
	    rccFree();
495
	    fprintf(stderr, "*** Unable to set source language (%s)\n", rccGetLanguageName(NULL, source_language_id));
496
	    exit(1);
497
	}
498
	if ((rccSetLanguage(NULL, target_language_id))||(!rccGetCurrentLanguageName(NULL))) {
499
	    rccFree();
500
	    fprintf(stderr, "*** Unable to set target language (%s)\n", rccGetLanguageName(NULL, target_language_id));
501
	    exit(1);
502
	}
503
    }
504
    
505
    switch (mode) {
506
	case MODE_STDIN:
507
	    Stdin(arg);
508
	break;
509
	case MODE_DIRECTORY:
510
	    Directory(arg);
511
	break;
512
	case MODE_FILE:
513
	    fprintf(stderr, "*** Mode (FILE) is not supported in current version\n");
514
	break;
515
	case MODE_FILELIST:
516
	    fprintf(stderr, "*** Mode (FILELIST) is not supported in current version\n");
517
	break;
518
    }
519
520
    
521
    rccFree();
522
523
    return 0;
524
}
525
526
// DS. Dynamicaly raise string length?
527
int Stdin(const char *arg) {
528
    char *res;
529
    char buf[16384];
530
531
    while (fgets(buf,16384,stdin)) {
532
	res = Translate(buf);
533
	fprintf(stdout, res?res:buf);
534
	if (res) free(res);
535
    }
536
    
537
    return 0;
538
}
539
540
char *Fullname(const char *path, const char *name) {
541
    char *res;
542
    
543
    res = (char*)malloc(strlen(path) + strlen(name) + 2);
544
    if (res) {
545
	if (path[strlen(path)-1] == '/')
546
	    sprintf(res, "%s%s",path,name);
547
	else
548
	    sprintf(res, "%s/%s",path,name);
549
    }
550
    return res;
551
}
552
553
// DS: We do not follow symbolic links (add option?)
554
// DS: Skipping everything begining with point (system files)
555
int Directory(const char *arg) {
556
    int err;
557
    struct stat st;
558
    
559
    DIR *dir;
560
    struct dirent *entry;
561
    char *res;
562
    char answer;
563
    
564
    char stmp[255];
565
    char *fn, *nfn;
566
    
567
    if (!arg) arg = ".";
568
    
569
    printf("Processing directory: %s\n", arg);
570
    
571
    dir = opendir(arg);
572
    if (!dir) {
573
	fprintf(stderr, "*** Failed to process directory: %s\n", arg);
574
	return -1;
575
    }
576
    
577
    entry = readdir(dir);
578
    while (entry) {
579
	if (entry->d_name[0] == '.') {
580
	    entry = readdir(dir);
581
	    continue;
582
	}
583
	
584
	res = Translate(entry->d_name);
585
	if (res) {
586
	    if (strcmp(res, entry->d_name)) {
587
		if (ask) {
588
		    printf("Rename \"%s\" to \"%s\" (y/[n]) ", entry->d_name, res);
589
		    scanf("%c", &answer);
590
		    if (answer != '\n') fgets(stmp, 255, stdin);
591
		    answer = ((answer=='y')||(answer=='Y'))?1:0;
592
		} else {
593
		    answer = 1;
594
		}
595
		
596
		if (answer) {
597
		    fn = Fullname(arg, entry->d_name);
598
		    nfn = Fullname(arg, res);
599
		    if ((fn)&&(nfn)) {
600
			if (!lstat(nfn, &st)) {
601
			    if (!ask) {
602
    				printf("Trying rename \"%s\" to \"%s\"\n", entry->d_name, res);
603
			    }
604
			    
605
			    if (S_ISDIR(st.st_mode)) {
606
				printf("*** Directory with that name exists, skipping\n");
607
				answer = 0;
608
			    } else {
609
				printf("*** File exists, overwrite (y/[n]) ");
610
				scanf("%c", &answer);
611
				if (answer != '\n') fgets(stmp, 255, stdin);
612
				answer = ((answer=='y')||(answer=='Y'))?1:0;
613
			    }
614
			}
615
			if (answer) {
616
			    err = rename(fn, nfn);
617
			}
618
		    } else err = ENOMEM;
619
		    
620
		    if (fn) free(fn);
621
		    if (nfn) free(nfn);
622
		    
623
		    if (err) {
624
    			printf("*** Renaming \"%s\" to \"%s\" is failed (errno: %u)\n", entry->d_name, res, errno);
625
		    } else if (!ask) {
626
    			printf("Rename completed: \"%s\" to \"%s\"\n", entry->d_name, res);
627
		    }
628
		}
629
	    }
630
	    free(res);
631
	}
632
	entry = readdir(dir);
633
    }
634
    closedir(dir);
635
    
636
    if (process_subdirs) {
637
	dir = opendir(arg);
638
	if (!dir) return 0;
639
	
640
	entry = readdir(dir);
641
	while (entry) {
642
	    if (entry->d_name[0] == '.') {
643
		entry = readdir(dir);
644
		continue;
645
	    }
646
647
	    fn = Fullname(arg, entry->d_name);
648
	    if (fn) {
649
		if ((!lstat(fn, &st))&&((S_ISDIR(st.st_mode)))) {
650
		    Directory(fn);
651
		}
652
		free(fn);
653
	    }
654
	    entry = readdir(dir);
655
	}
656
	closedir(dir);
657
    }
658
    
659
    
660
    return 0;
661
}
662
663
char *Translate(const char *source) {
664
    rcc_string rccstring;
665
    char *recoded, *stmp;
666
667
    if (strlen(source)<2) return NULL;
668
669
    if (source_language_id != target_language_id) {
670
	rccSetLanguage(NULL, source_language_id);
671
    }
672
673
    if (efrom) rccstring = rccFromCharset(NULL, efrom, source);
674
    else rccstring = rccFrom(NULL, source_class_id, source);
675
    
676
    if (!rccstring) return NULL;
677
678
    if (source_language_id != target_language_id)
679
	rccSetLanguage(NULL, target_language_id);
680
681
    if (eto) {
682
	if (translate = RCC_OPTION_TRANSLATE_OFF) {
683
	    stmp = rccTo(NULL, target_class_id, rccstring);
684
	    if (stmp) {
685
		recoded = rccRecodeCharsets(NULL, "UTF-8", eto, stmp);
686
		if (recoded)  free(stmp);
687
		else recoded = stmp;
688
	    } else recoded = NULL;
689
	    
690
	} else {
691
	    recoded = rccToCharset(NULL, eto, rccstring);
692
	}
693
    } else recoded = rccTo(NULL, target_class_id, rccstring);
694
    
695
    free(rccstring);
696
    return recoded;        
697
}
698