util.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515
  1. /* Various utilities
  2. Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
  3. 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
  4. Written 1994, 1995, 1996 by:
  5. Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
  6. Jakub Jelinek, Mauricio Plaza.
  7. The file_date routine is mostly from GNU's fileutils package,
  8. written by Richard Stallman and David MacKenzie.
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  20. /** \file
  21. * \brief Source: various utilities
  22. */
  23. #include <config.h>
  24. #include <ctype.h>
  25. #include <limits.h>
  26. #include <stdarg.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <fcntl.h>
  31. #include <sys/time.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <unistd.h>
  35. #include "lib/global.h"
  36. #include "lib/tty/win.h" /* xterm_flag */
  37. #include "lib/mcconfig.h"
  38. #include "lib/fileloc.h"
  39. #include "lib/vfs/mc-vfs/vfs.h"
  40. #include "lib/strutil.h"
  41. #include "lib/util.h"
  42. #include "src/filemanager/filegui.h"
  43. #include "src/filemanager/file.h" /* copy_file_file() */
  44. #include "src/main.h" /* home_dir, eight_bit_clean */
  45. /*** global variables ****************************************************************************/
  46. /*** file scope macro definitions ****************************************************************/
  47. #define ismode(n,m) ((n & m) == m)
  48. /* Number of attempts to create a temporary file */
  49. #ifndef TMP_MAX
  50. #define TMP_MAX 16384
  51. #endif /* !TMP_MAX */
  52. #define TMP_SUFFIX ".tmp"
  53. #define ASCII_A (0x40 + 1)
  54. #define ASCII_Z (0x40 + 26)
  55. #define ASCII_a (0x60 + 1)
  56. #define ASCII_z (0x60 + 26)
  57. /*** file scope type declarations ****************************************************************/
  58. /*** file scope variables ************************************************************************/
  59. /*** file scope functions ************************************************************************/
  60. /* --------------------------------------------------------------------------------------------- */
  61. static inline int
  62. is_7bit_printable (unsigned char c)
  63. {
  64. return (c > 31 && c < 127);
  65. }
  66. /* --------------------------------------------------------------------------------------------- */
  67. static inline int
  68. is_iso_printable (unsigned char c)
  69. {
  70. return ((c > 31 && c < 127) || c >= 160);
  71. }
  72. /* --------------------------------------------------------------------------------------------- */
  73. static inline int
  74. is_8bit_printable (unsigned char c)
  75. {
  76. /* "Full 8 bits output" doesn't work on xterm */
  77. if (xterm_flag)
  78. return is_iso_printable (c);
  79. return (c > 31 && c != 127 && c != 155);
  80. }
  81. /* --------------------------------------------------------------------------------------------- */
  82. static char *
  83. resolve_symlinks (const char *path)
  84. {
  85. char *buf, *buf2, *q, *r, c;
  86. int len;
  87. struct stat mybuf;
  88. const char *p;
  89. if (*path != PATH_SEP)
  90. return NULL;
  91. r = buf = g_malloc (MC_MAXPATHLEN);
  92. buf2 = g_malloc (MC_MAXPATHLEN);
  93. *r++ = PATH_SEP;
  94. *r = 0;
  95. p = path;
  96. for (;;)
  97. {
  98. q = strchr (p + 1, PATH_SEP);
  99. if (!q)
  100. {
  101. q = strchr (p + 1, 0);
  102. if (q == p + 1)
  103. break;
  104. }
  105. c = *q;
  106. *q = 0;
  107. if (mc_lstat (path, &mybuf) < 0)
  108. {
  109. g_free (buf);
  110. g_free (buf2);
  111. *q = c;
  112. return NULL;
  113. }
  114. if (!S_ISLNK (mybuf.st_mode))
  115. strcpy (r, p + 1);
  116. else
  117. {
  118. len = mc_readlink (path, buf2, MC_MAXPATHLEN - 1);
  119. if (len < 0)
  120. {
  121. g_free (buf);
  122. g_free (buf2);
  123. *q = c;
  124. return NULL;
  125. }
  126. buf2[len] = 0;
  127. if (*buf2 == PATH_SEP)
  128. strcpy (buf, buf2);
  129. else
  130. strcpy (r, buf2);
  131. }
  132. canonicalize_pathname (buf);
  133. r = strchr (buf, 0);
  134. if (!*r || *(r - 1) != PATH_SEP)
  135. {
  136. *r++ = PATH_SEP;
  137. *r = 0;
  138. }
  139. *q = c;
  140. p = q;
  141. if (!c)
  142. break;
  143. }
  144. if (!*buf)
  145. strcpy (buf, PATH_SEP_STR);
  146. else if (*(r - 1) == PATH_SEP && r != buf + 1)
  147. *(r - 1) = 0;
  148. g_free (buf2);
  149. return buf;
  150. }
  151. /* --------------------------------------------------------------------------------------------- */
  152. static gboolean
  153. mc_util_write_backup_content (const char *from_file_name, const char *to_file_name)
  154. {
  155. FILE *backup_fd;
  156. char *contents;
  157. gsize length;
  158. gboolean ret1 = TRUE;
  159. if (!g_file_get_contents (from_file_name, &contents, &length, NULL))
  160. return FALSE;
  161. backup_fd = fopen (to_file_name, "w");
  162. if (backup_fd == NULL)
  163. {
  164. g_free (contents);
  165. return FALSE;
  166. }
  167. if (fwrite ((const void *) contents, 1, length, backup_fd) != length)
  168. ret1 = FALSE;
  169. {
  170. int ret2;
  171. ret2 = fflush (backup_fd);
  172. ret2 = fclose (backup_fd);
  173. }
  174. g_free (contents);
  175. return ret1;
  176. }
  177. /* --------------------------------------------------------------------------------------------- */
  178. /*** public functions ****************************************************************************/
  179. /* --------------------------------------------------------------------------------------------- */
  180. int
  181. is_printable (int c)
  182. {
  183. c &= 0xff;
  184. #ifdef HAVE_CHARSET
  185. /* "Display bits" is ignored, since the user controls the output
  186. by setting the output codepage */
  187. return is_8bit_printable (c);
  188. #else
  189. if (!eight_bit_clean)
  190. return is_7bit_printable (c);
  191. if (full_eight_bits)
  192. {
  193. return is_8bit_printable (c);
  194. }
  195. else
  196. return is_iso_printable (c);
  197. #endif /* !HAVE_CHARSET */
  198. }
  199. /* --------------------------------------------------------------------------------------------- */
  200. /**
  201. * Quote the filename for the purpose of inserting it into the command
  202. * line. If quote_percent is 1, replace "%" with "%%" - the percent is
  203. * processed by the mc command line.
  204. */
  205. char *
  206. name_quote (const char *s, int quote_percent)
  207. {
  208. char *ret, *d;
  209. d = ret = g_malloc (strlen (s) * 2 + 2 + 1);
  210. if (*s == '-')
  211. {
  212. *d++ = '.';
  213. *d++ = '/';
  214. }
  215. for (; *s; s++, d++)
  216. {
  217. switch (*s)
  218. {
  219. case '%':
  220. if (quote_percent)
  221. *d++ = '%';
  222. break;
  223. case '\'':
  224. case '\\':
  225. case '\r':
  226. case '\n':
  227. case '\t':
  228. case '"':
  229. case ';':
  230. case ' ':
  231. case '?':
  232. case '|':
  233. case '[':
  234. case ']':
  235. case '{':
  236. case '}':
  237. case '<':
  238. case '>':
  239. case '`':
  240. case '!':
  241. case '$':
  242. case '&':
  243. case '*':
  244. case '(':
  245. case ')':
  246. *d++ = '\\';
  247. break;
  248. case '~':
  249. case '#':
  250. if (d == ret)
  251. *d++ = '\\';
  252. break;
  253. }
  254. *d = *s;
  255. }
  256. *d = '\0';
  257. return ret;
  258. }
  259. /* --------------------------------------------------------------------------------------------- */
  260. char *
  261. fake_name_quote (const char *s, int quote_percent)
  262. {
  263. (void) quote_percent;
  264. return g_strdup (s);
  265. }
  266. /* --------------------------------------------------------------------------------------------- */
  267. /**
  268. * path_trunc() is the same as str_trunc() but
  269. * it deletes possible password from path for security
  270. * reasons.
  271. */
  272. const char *
  273. path_trunc (const char *path, size_t trunc_len)
  274. {
  275. char *secure_path = strip_password (g_strdup (path), 1);
  276. const char *ret = str_trunc (secure_path, trunc_len);
  277. g_free (secure_path);
  278. return ret;
  279. }
  280. /* --------------------------------------------------------------------------------------------- */
  281. const char *
  282. size_trunc (double size, gboolean use_si)
  283. {
  284. static char x[BUF_TINY];
  285. long int divisor = 1;
  286. const char *xtra = "";
  287. if (size > 999999999L)
  288. {
  289. divisor = use_si ? 1000 : 1024;
  290. xtra = use_si ? "k" : "K";
  291. if (size / divisor > 999999999L)
  292. {
  293. divisor = use_si ? (1000 * 1000) : (1024 * 1024);
  294. xtra = use_si ? "m" : "M";
  295. }
  296. }
  297. g_snprintf (x, sizeof (x), "%.0f%s", (size / divisor), xtra);
  298. return x;
  299. }
  300. /* --------------------------------------------------------------------------------------------- */
  301. const char *
  302. size_trunc_sep (double size, gboolean use_si)
  303. {
  304. static char x[60];
  305. int count;
  306. const char *p, *y;
  307. char *d;
  308. p = y = size_trunc (size, use_si);
  309. p += strlen (p) - 1;
  310. d = x + sizeof (x) - 1;
  311. *d-- = 0;
  312. while (p >= y && isalpha ((unsigned char) *p))
  313. *d-- = *p--;
  314. for (count = 0; p >= y; count++)
  315. {
  316. if (count == 3)
  317. {
  318. *d-- = ',';
  319. count = 0;
  320. }
  321. *d-- = *p--;
  322. }
  323. d++;
  324. if (*d == ',')
  325. d++;
  326. return d;
  327. }
  328. /* --------------------------------------------------------------------------------------------- */
  329. /**
  330. * Print file SIZE to BUFFER, but don't exceed LEN characters,
  331. * not including trailing 0. BUFFER should be at least LEN+1 long.
  332. * This function is called for every file on panels, so avoid
  333. * floating point by any means.
  334. *
  335. * Units: size units (filesystem sizes are 1K blocks)
  336. * 0=bytes, 1=Kbytes, 2=Mbytes, etc.
  337. */
  338. void
  339. size_trunc_len (char *buffer, unsigned int len, off_t size, int units, gboolean use_si)
  340. {
  341. /* Avoid taking power for every file. */
  342. static const off_t power10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
  343. 1000000000
  344. };
  345. static const char *const suffix[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL };
  346. static const char *const suffix_lc[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL };
  347. int j = 0;
  348. int size_remain;
  349. if (len == 0)
  350. len = 9;
  351. /*
  352. * recalculate from 1024 base to 1000 base if units>0
  353. * We can't just multiply by 1024 - that might cause overflow
  354. * if off_t type is too small
  355. */
  356. if (units && use_si)
  357. {
  358. for (j = 0; j < units; j++)
  359. {
  360. size_remain = ((size % 125) * 1024) / 1000; /* size mod 125, recalculated */
  361. size = size / 125; /* 128/125 = 1024/1000 */
  362. size = size * 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
  363. size += size_remain; /* Re-add remainder lost by division/multiplication */
  364. }
  365. }
  366. for (j = units; suffix[j] != NULL; j++)
  367. {
  368. if (size == 0)
  369. {
  370. if (j == units)
  371. {
  372. /* Empty files will print "0" even with minimal width. */
  373. g_snprintf (buffer, len + 1, "0");
  374. break;
  375. }
  376. /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
  377. g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s",
  378. (j > 1) ? (use_si ? suffix_lc[j - 1] : suffix[j - 1]) : "B");
  379. break;
  380. }
  381. if (size < power10[len - (j > 0)])
  382. {
  383. g_snprintf (buffer, len + 1, "%lu%s", (unsigned long) size,
  384. use_si ? suffix_lc[j] : suffix[j]);
  385. break;
  386. }
  387. /* Powers of 1000 or 1024, with rounding. */
  388. if (use_si)
  389. size = (size + 500) / 1000;
  390. else
  391. size = (size + 512) >> 10;
  392. }
  393. }
  394. /* --------------------------------------------------------------------------------------------- */
  395. const char *
  396. string_perm (mode_t mode_bits)
  397. {
  398. static char mode[11];
  399. strcpy (mode, "----------");
  400. if (S_ISDIR (mode_bits))
  401. mode[0] = 'd';
  402. if (S_ISCHR (mode_bits))
  403. mode[0] = 'c';
  404. if (S_ISBLK (mode_bits))
  405. mode[0] = 'b';
  406. if (S_ISLNK (mode_bits))
  407. mode[0] = 'l';
  408. if (S_ISFIFO (mode_bits))
  409. mode[0] = 'p';
  410. if (S_ISNAM (mode_bits))
  411. mode[0] = 'n';
  412. if (S_ISSOCK (mode_bits))
  413. mode[0] = 's';
  414. if (S_ISDOOR (mode_bits))
  415. mode[0] = 'D';
  416. if (ismode (mode_bits, S_IXOTH))
  417. mode[9] = 'x';
  418. if (ismode (mode_bits, S_IWOTH))
  419. mode[8] = 'w';
  420. if (ismode (mode_bits, S_IROTH))
  421. mode[7] = 'r';
  422. if (ismode (mode_bits, S_IXGRP))
  423. mode[6] = 'x';
  424. if (ismode (mode_bits, S_IWGRP))
  425. mode[5] = 'w';
  426. if (ismode (mode_bits, S_IRGRP))
  427. mode[4] = 'r';
  428. if (ismode (mode_bits, S_IXUSR))
  429. mode[3] = 'x';
  430. if (ismode (mode_bits, S_IWUSR))
  431. mode[2] = 'w';
  432. if (ismode (mode_bits, S_IRUSR))
  433. mode[1] = 'r';
  434. #ifdef S_ISUID
  435. if (ismode (mode_bits, S_ISUID))
  436. mode[3] = (mode[3] == 'x') ? 's' : 'S';
  437. #endif /* S_ISUID */
  438. #ifdef S_ISGID
  439. if (ismode (mode_bits, S_ISGID))
  440. mode[6] = (mode[6] == 'x') ? 's' : 'S';
  441. #endif /* S_ISGID */
  442. #ifdef S_ISVTX
  443. if (ismode (mode_bits, S_ISVTX))
  444. mode[9] = (mode[9] == 'x') ? 't' : 'T';
  445. #endif /* S_ISVTX */
  446. return mode;
  447. }
  448. /* --------------------------------------------------------------------------------------------- */
  449. /**
  450. * p: string which might contain an url with a password (this parameter is
  451. * modified in place).
  452. * has_prefix = 0: The first parameter is an url without a prefix
  453. * (user[:pass]@]machine[:port][remote-dir). Delete
  454. * the password.
  455. * has_prefix = 1: Search p for known url prefixes. If found delete
  456. * the password from the url.
  457. * Caveat: only the first url is found
  458. */
  459. char *
  460. strip_password (char *p, int has_prefix)
  461. {
  462. static const struct
  463. {
  464. const char *name;
  465. size_t len;
  466. } prefixes[] =
  467. {
  468. /* *INDENT-OFF* */
  469. { "/#ftp:", 6 },
  470. { "ftp://", 6 },
  471. { "/#smb:", 6 },
  472. { "smb://", 6 },
  473. { "/#sh:", 5 },
  474. { "sh://", 5 },
  475. { "ssh://", 6 }
  476. /* *INDENT-ON* */
  477. };
  478. char *at, *inner_colon, *dir;
  479. size_t i;
  480. char *result = p;
  481. for (i = 0; i < sizeof (prefixes) / sizeof (prefixes[0]); i++)
  482. {
  483. char *q;
  484. if (has_prefix)
  485. {
  486. q = strstr (p, prefixes[i].name);
  487. if (q == NULL)
  488. continue;
  489. else
  490. p = q + prefixes[i].len;
  491. }
  492. dir = strchr (p, PATH_SEP);
  493. if (dir != NULL)
  494. *dir = '\0';
  495. /* search for any possible user */
  496. at = strrchr (p, '@');
  497. if (dir)
  498. *dir = PATH_SEP;
  499. /* We have a username */
  500. if (at)
  501. {
  502. inner_colon = memchr (p, ':', at - p);
  503. if (inner_colon)
  504. memmove (inner_colon, at, strlen (at) + 1);
  505. }
  506. break;
  507. }
  508. return (result);
  509. }
  510. /* --------------------------------------------------------------------------------------------- */
  511. const char *
  512. strip_home_and_password (const char *dir)
  513. {
  514. size_t len;
  515. static char newdir[MC_MAXPATHLEN];
  516. len = strlen (home_dir);
  517. if (home_dir != NULL && strncmp (dir, home_dir, len) == 0 &&
  518. (dir[len] == PATH_SEP || dir[len] == '\0'))
  519. {
  520. newdir[0] = '~';
  521. g_strlcpy (&newdir[1], &dir[len], sizeof (newdir) - 1);
  522. return newdir;
  523. }
  524. /* We do not strip homes in /#ftp tree, I do not like ~'s there
  525. (see ftpfs.c why) */
  526. g_strlcpy (newdir, dir, sizeof (newdir));
  527. strip_password (newdir, 1);
  528. return newdir;
  529. }
  530. /* --------------------------------------------------------------------------------------------- */
  531. const char *
  532. extension (const char *filename)
  533. {
  534. const char *d = strrchr (filename, '.');
  535. return (d != NULL) ? d + 1 : "";
  536. }
  537. /* --------------------------------------------------------------------------------------------- */
  538. int
  539. check_for_default (const char *default_file, const char *file)
  540. {
  541. if (!exist_file (file))
  542. {
  543. FileOpContext *ctx;
  544. FileOpTotalContext *tctx;
  545. if (!exist_file (default_file))
  546. return -1;
  547. ctx = file_op_context_new (OP_COPY);
  548. tctx = file_op_total_context_new ();
  549. file_op_context_create_ui (ctx, 0, FALSE);
  550. copy_file_file (tctx, ctx, default_file, file);
  551. file_op_total_context_destroy (tctx);
  552. file_op_context_destroy (ctx);
  553. }
  554. return 0;
  555. }
  556. /* --------------------------------------------------------------------------------------------- */
  557. char *
  558. load_mc_home_file (const char *from, const char *filename, char **allocated_filename)
  559. {
  560. char *hintfile_base, *hintfile;
  561. char *lang;
  562. char *data;
  563. hintfile_base = g_build_filename (from, filename, (char *) NULL);
  564. lang = guess_message_value ();
  565. hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
  566. if (!g_file_get_contents (hintfile, &data, NULL, NULL))
  567. {
  568. /* Fall back to the two-letter language code */
  569. if (lang[0] != '\0' && lang[1] != '\0')
  570. lang[2] = '\0';
  571. g_free (hintfile);
  572. hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
  573. if (!g_file_get_contents (hintfile, &data, NULL, NULL))
  574. {
  575. g_free (hintfile);
  576. hintfile = hintfile_base;
  577. g_file_get_contents (hintfile_base, &data, NULL, NULL);
  578. }
  579. }
  580. g_free (lang);
  581. if (hintfile != hintfile_base)
  582. g_free (hintfile_base);
  583. if (allocated_filename != NULL)
  584. *allocated_filename = hintfile;
  585. else
  586. g_free (hintfile);
  587. return data;
  588. }
  589. /* --------------------------------------------------------------------------------------------- */
  590. const char *
  591. extract_line (const char *s, const char *top)
  592. {
  593. static char tmp_line[BUF_MEDIUM];
  594. char *t = tmp_line;
  595. while (*s && *s != '\n' && (size_t) (t - tmp_line) < sizeof (tmp_line) - 1 && s < top)
  596. *t++ = *s++;
  597. *t = 0;
  598. return tmp_line;
  599. }
  600. /* --------------------------------------------------------------------------------------------- */
  601. /**
  602. * The basename routine
  603. */
  604. const char *
  605. x_basename (const char *s)
  606. {
  607. const char *where;
  608. return ((where = strrchr (s, PATH_SEP))) ? where + 1 : s;
  609. }
  610. /* --------------------------------------------------------------------------------------------- */
  611. const char *
  612. unix_error_string (int error_num)
  613. {
  614. static char buffer[BUF_LARGE];
  615. gchar *strerror_currentlocale;
  616. strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
  617. g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
  618. g_free (strerror_currentlocale);
  619. return buffer;
  620. }
  621. /* --------------------------------------------------------------------------------------------- */
  622. const char *
  623. skip_separators (const char *s)
  624. {
  625. const char *su = s;
  626. for (; *su; str_cnext_char (&su))
  627. if (*su != ' ' && *su != '\t' && *su != ',')
  628. break;
  629. return su;
  630. }
  631. /* --------------------------------------------------------------------------------------------- */
  632. const char *
  633. skip_numbers (const char *s)
  634. {
  635. const char *su = s;
  636. for (; *su; str_cnext_char (&su))
  637. if (!str_isdigit (su))
  638. break;
  639. return su;
  640. }
  641. /* --------------------------------------------------------------------------------------------- */
  642. /**
  643. * Remove all control sequences from the argument string. We define
  644. * "control sequence", in a sort of pidgin BNF, as follows:
  645. *
  646. * control-seq = Esc non-'['
  647. * | Esc '[' (0 or more digits or ';' or '?') (any other char)
  648. *
  649. * This scheme works for all the terminals described in my termcap /
  650. * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
  651. * terminals. If I hear from a single person who uses such a terminal
  652. * with MC, I'll be glad to add support for it. (Dugan)
  653. * Non-printable characters are also removed.
  654. */
  655. char *
  656. strip_ctrl_codes (char *s)
  657. {
  658. char *w; /* Current position where the stripped data is written */
  659. char *r; /* Current position where the original data is read */
  660. char *n;
  661. if (!s)
  662. return 0;
  663. for (w = s, r = s; *r;)
  664. {
  665. if (*r == ESC_CHAR)
  666. {
  667. /* Skip the control sequence's arguments */ ;
  668. /* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
  669. if (*(++r) == '[' || *r == '(')
  670. {
  671. /* strchr() matches trailing binary 0 */
  672. while (*(++r) && strchr ("0123456789;?", *r));
  673. }
  674. else if (*r == ']')
  675. {
  676. /*
  677. * Skip xterm's OSC (Operating System Command)
  678. * http://www.xfree86.org/current/ctlseqs.html
  679. * OSC P s ; P t ST
  680. * OSC P s ; P t BEL
  681. */
  682. char *new_r = r;
  683. for (; *new_r; ++new_r)
  684. {
  685. switch (*new_r)
  686. {
  687. /* BEL */
  688. case '\a':
  689. r = new_r;
  690. goto osc_out;
  691. case ESC_CHAR:
  692. /* ST */
  693. if (*(new_r + 1) == '\\')
  694. {
  695. r = new_r + 1;
  696. goto osc_out;
  697. }
  698. }
  699. }
  700. osc_out:;
  701. }
  702. /*
  703. * Now we are at the last character of the sequence.
  704. * Skip it unless it's binary 0.
  705. */
  706. if (*r)
  707. r++;
  708. continue;
  709. }
  710. n = str_get_next_char (r);
  711. if (str_isprint (r))
  712. {
  713. memmove (w, r, n - r);
  714. w += n - r;
  715. }
  716. r = n;
  717. }
  718. *w = 0;
  719. return s;
  720. }
  721. /* --------------------------------------------------------------------------------------------- */
  722. enum compression_type
  723. get_compression_type (int fd, const char *name)
  724. {
  725. unsigned char magic[16];
  726. size_t str_len;
  727. /* Read the magic signature */
  728. if (mc_read (fd, (char *) magic, 4) != 4)
  729. return COMPRESSION_NONE;
  730. /* GZIP_MAGIC and OLD_GZIP_MAGIC */
  731. if (magic[0] == 037 && (magic[1] == 0213 || magic[1] == 0236))
  732. {
  733. return COMPRESSION_GZIP;
  734. }
  735. /* PKZIP_MAGIC */
  736. if (magic[0] == 0120 && magic[1] == 0113 && magic[2] == 003 && magic[3] == 004)
  737. {
  738. /* Read compression type */
  739. mc_lseek (fd, 8, SEEK_SET);
  740. if (mc_read (fd, (char *) magic, 2) != 2)
  741. return COMPRESSION_NONE;
  742. /* Gzip can handle only deflated (8) or stored (0) files */
  743. if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
  744. return COMPRESSION_NONE;
  745. /* Compatible with gzip */
  746. return COMPRESSION_GZIP;
  747. }
  748. /* PACK_MAGIC and LZH_MAGIC and compress magic */
  749. if (magic[0] == 037 && (magic[1] == 036 || magic[1] == 0240 || magic[1] == 0235))
  750. {
  751. /* Compatible with gzip */
  752. return COMPRESSION_GZIP;
  753. }
  754. /* BZIP and BZIP2 files */
  755. if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
  756. {
  757. switch (magic[2])
  758. {
  759. case '0':
  760. return COMPRESSION_BZIP;
  761. case 'h':
  762. return COMPRESSION_BZIP2;
  763. }
  764. }
  765. /* Support for LZMA (only utils format with magic in header).
  766. * This is the default format of LZMA utils 4.32.1 and later. */
  767. if (mc_read (fd, (char *) magic + 4, 2) != 2)
  768. return COMPRESSION_NONE;
  769. /* LZMA utils format */
  770. if (magic[0] == 0xFF
  771. && magic[1] == 'L'
  772. && magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A' && magic[5] == 0x00)
  773. return COMPRESSION_LZMA;
  774. /* XZ compression magic */
  775. if (magic[0] == 0xFD
  776. && magic[1] == 0x37
  777. && magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
  778. return COMPRESSION_XZ;
  779. str_len = strlen (name);
  780. /* HACK: we must belive to extention of LZMA file :) ... */
  781. if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0) ||
  782. (str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
  783. return COMPRESSION_LZMA;
  784. return COMPRESSION_NONE;
  785. }
  786. /* --------------------------------------------------------------------------------------------- */
  787. const char *
  788. decompress_extension (int type)
  789. {
  790. switch (type)
  791. {
  792. case COMPRESSION_GZIP:
  793. return "#ugz";
  794. case COMPRESSION_BZIP:
  795. return "#ubz";
  796. case COMPRESSION_BZIP2:
  797. return "#ubz2";
  798. case COMPRESSION_LZMA:
  799. return "#ulzma";
  800. case COMPRESSION_XZ:
  801. return "#uxz";
  802. }
  803. /* Should never reach this place */
  804. fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
  805. return 0;
  806. }
  807. /* --------------------------------------------------------------------------------------------- */
  808. void
  809. wipe_password (char *passwd)
  810. {
  811. char *p = passwd;
  812. if (!p)
  813. return;
  814. for (; *p; p++)
  815. *p = 0;
  816. g_free (passwd);
  817. }
  818. /* --------------------------------------------------------------------------------------------- */
  819. /**
  820. * Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
  821. * @returns a newly allocated string
  822. */
  823. char *
  824. convert_controls (const char *p)
  825. {
  826. char *valcopy = g_strdup (p);
  827. char *q;
  828. /* Parse the escape special character */
  829. for (q = valcopy; *p;)
  830. {
  831. if (*p == '\\')
  832. {
  833. p++;
  834. if ((*p == 'e') || (*p == 'E'))
  835. {
  836. p++;
  837. *q++ = ESC_CHAR;
  838. }
  839. }
  840. else
  841. {
  842. if (*p == '^')
  843. {
  844. p++;
  845. if (*p == '^')
  846. *q++ = *p++;
  847. else
  848. {
  849. char c = (*p | 0x20);
  850. if (c >= 'a' && c <= 'z')
  851. {
  852. *q++ = c - 'a' + 1;
  853. p++;
  854. }
  855. else if (*p)
  856. p++;
  857. }
  858. }
  859. else
  860. *q++ = *p++;
  861. }
  862. }
  863. *q = 0;
  864. return valcopy;
  865. }
  866. /* --------------------------------------------------------------------------------------------- */
  867. /**
  868. * Finds out a relative path from first to second, i.e. goes as many ..
  869. * as needed up in first and then goes down using second
  870. */
  871. char *
  872. diff_two_paths (const char *first, const char *second)
  873. {
  874. char *p, *q, *r, *s, *buf = NULL;
  875. int i, j, prevlen = -1, currlen;
  876. char *my_first = NULL, *my_second = NULL;
  877. my_first = resolve_symlinks (first);
  878. if (my_first == NULL)
  879. return NULL;
  880. my_second = resolve_symlinks (second);
  881. if (my_second == NULL)
  882. {
  883. g_free (my_first);
  884. return NULL;
  885. }
  886. for (j = 0; j < 2; j++)
  887. {
  888. p = my_first;
  889. q = my_second;
  890. for (;;)
  891. {
  892. r = strchr (p, PATH_SEP);
  893. s = strchr (q, PATH_SEP);
  894. if (!r || !s)
  895. break;
  896. *r = 0;
  897. *s = 0;
  898. if (strcmp (p, q))
  899. {
  900. *r = PATH_SEP;
  901. *s = PATH_SEP;
  902. break;
  903. }
  904. else
  905. {
  906. *r = PATH_SEP;
  907. *s = PATH_SEP;
  908. }
  909. p = r + 1;
  910. q = s + 1;
  911. }
  912. p--;
  913. for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++);
  914. currlen = (i + 1) * 3 + strlen (q) + 1;
  915. if (j)
  916. {
  917. if (currlen < prevlen)
  918. g_free (buf);
  919. else
  920. {
  921. g_free (my_first);
  922. g_free (my_second);
  923. return buf;
  924. }
  925. }
  926. p = buf = g_malloc (currlen);
  927. prevlen = currlen;
  928. for (; i >= 0; i--, p += 3)
  929. strcpy (p, "../");
  930. strcpy (p, q);
  931. }
  932. g_free (my_first);
  933. g_free (my_second);
  934. return buf;
  935. }
  936. /* --------------------------------------------------------------------------------------------- */
  937. /**
  938. * If filename is NULL, then we just append PATH_SEP to the dir
  939. */
  940. char *
  941. concat_dir_and_file (const char *dir, const char *file)
  942. {
  943. int i = strlen (dir);
  944. if (dir[i - 1] == PATH_SEP)
  945. return g_strconcat (dir, file, (char *) NULL);
  946. else
  947. return g_strconcat (dir, PATH_SEP_STR, file, (char *) NULL);
  948. }
  949. /* --------------------------------------------------------------------------------------------- */
  950. /**
  951. * Append text to GList, remove all entries with the same text
  952. */
  953. GList *
  954. list_append_unique (GList * list, char *text)
  955. {
  956. GList *lc_link;
  957. /*
  958. * Go to the last position and traverse the list backwards
  959. * starting from the second last entry to make sure that we
  960. * are not removing the current link.
  961. */
  962. list = g_list_append (list, text);
  963. list = g_list_last (list);
  964. lc_link = g_list_previous (list);
  965. while (lc_link != NULL)
  966. {
  967. GList *newlink;
  968. newlink = g_list_previous (lc_link);
  969. if (strcmp ((char *) lc_link->data, text) == 0)
  970. {
  971. GList *tmp;
  972. g_free (lc_link->data);
  973. tmp = g_list_remove_link (list, lc_link);
  974. g_list_free_1 (lc_link);
  975. }
  976. lc_link = newlink;
  977. }
  978. return list;
  979. }
  980. /* --------------------------------------------------------------------------------------------- */
  981. /* Following code heavily borrows from libiberty, mkstemps.c */
  982. /*
  983. * Arguments:
  984. * pname (output) - pointer to the name of the temp file (needs g_free).
  985. * NULL if the function fails.
  986. * prefix - part of the filename before the random part.
  987. * Prepend $TMPDIR or /tmp if there are no path separators.
  988. * suffix - if not NULL, part of the filename after the random part.
  989. *
  990. * Result:
  991. * handle of the open file or -1 if couldn't open any.
  992. */
  993. int
  994. mc_mkstemps (char **pname, const char *prefix, const char *suffix)
  995. {
  996. static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  997. static unsigned long value;
  998. struct timeval tv;
  999. char *tmpbase;
  1000. char *tmpname;
  1001. char *XXXXXX;
  1002. int count;
  1003. if (strchr (prefix, PATH_SEP) == NULL)
  1004. {
  1005. /* Add prefix first to find the position of XXXXXX */
  1006. tmpbase = concat_dir_and_file (mc_tmpdir (), prefix);
  1007. }
  1008. else
  1009. {
  1010. tmpbase = g_strdup (prefix);
  1011. }
  1012. tmpname = g_strconcat (tmpbase, "XXXXXX", suffix, (char *) NULL);
  1013. *pname = tmpname;
  1014. XXXXXX = &tmpname[strlen (tmpbase)];
  1015. g_free (tmpbase);
  1016. /* Get some more or less random data. */
  1017. gettimeofday (&tv, NULL);
  1018. value += (tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
  1019. for (count = 0; count < TMP_MAX; ++count)
  1020. {
  1021. unsigned long v = value;
  1022. int fd;
  1023. /* Fill in the random bits. */
  1024. XXXXXX[0] = letters[v % 62];
  1025. v /= 62;
  1026. XXXXXX[1] = letters[v % 62];
  1027. v /= 62;
  1028. XXXXXX[2] = letters[v % 62];
  1029. v /= 62;
  1030. XXXXXX[3] = letters[v % 62];
  1031. v /= 62;
  1032. XXXXXX[4] = letters[v % 62];
  1033. v /= 62;
  1034. XXXXXX[5] = letters[v % 62];
  1035. fd = open (tmpname, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, S_IRUSR | S_IWUSR);
  1036. if (fd >= 0)
  1037. {
  1038. /* Successfully created. */
  1039. return fd;
  1040. }
  1041. /* This is a random value. It is only necessary that the next
  1042. TMP_MAX values generated by adding 7777 to VALUE are different
  1043. with (module 2^32). */
  1044. value += 7777;
  1045. }
  1046. /* Unsuccessful. Free the filename. */
  1047. g_free (tmpname);
  1048. *pname = NULL;
  1049. return -1;
  1050. }
  1051. /* --------------------------------------------------------------------------------------------- */
  1052. /**
  1053. * Read and restore position for the given filename.
  1054. * If there is no stored data, return line 1 and col 0.
  1055. */
  1056. void
  1057. load_file_position (const char *filename, long *line, long *column, off_t * offset,
  1058. GArray ** bookmarks)
  1059. {
  1060. char *fn;
  1061. FILE *f;
  1062. char buf[MC_MAXPATHLEN + 100];
  1063. const size_t len = strlen (filename);
  1064. /* defaults */
  1065. *line = 1;
  1066. *column = 0;
  1067. *offset = 0;
  1068. /* open file with positions */
  1069. fn = g_build_filename (home_dir, MC_USERCONF_DIR, MC_FILEPOS_FILE, NULL);
  1070. f = fopen (fn, "r");
  1071. g_free (fn);
  1072. if (f == NULL)
  1073. return;
  1074. /* prepare array for serialized bookmarks */
  1075. *bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
  1076. while (fgets (buf, sizeof (buf), f) != NULL)
  1077. {
  1078. const char *p;
  1079. gchar **pos_tokens;
  1080. /* check if the filename matches the beginning of string */
  1081. if (strncmp (buf, filename, len) != 0)
  1082. continue;
  1083. /* followed by single space */
  1084. if (buf[len] != ' ')
  1085. continue;
  1086. /* and string without spaces */
  1087. p = &buf[len + 1];
  1088. if (strchr (p, ' ') != NULL)
  1089. continue;
  1090. pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
  1091. if (pos_tokens[0] == NULL)
  1092. {
  1093. *line = 1;
  1094. *column = 0;
  1095. *offset = 0;
  1096. }
  1097. else
  1098. {
  1099. *line = strtol (pos_tokens[0], NULL, 10);
  1100. if (pos_tokens[1] == NULL)
  1101. {
  1102. *column = 0;
  1103. *offset = 0;
  1104. }
  1105. else
  1106. {
  1107. *column = strtol (pos_tokens[1], NULL, 10);
  1108. if (pos_tokens[2] == NULL)
  1109. *offset = 0;
  1110. else
  1111. {
  1112. size_t i;
  1113. *offset = strtoll (pos_tokens[2], NULL, 10);
  1114. for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
  1115. {
  1116. size_t val;
  1117. val = strtoul (pos_tokens[3 + i], NULL, 10);
  1118. g_array_append_val (*bookmarks, val);
  1119. }
  1120. }
  1121. }
  1122. }
  1123. g_strfreev (pos_tokens);
  1124. }
  1125. fclose (f);
  1126. }
  1127. /* --------------------------------------------------------------------------------------------- */
  1128. /**
  1129. * Save position for the given file
  1130. */
  1131. void
  1132. save_file_position (const char *filename, long line, long column, off_t offset, GArray * bookmarks)
  1133. {
  1134. static size_t filepos_max_saved_entries = 0;
  1135. char *fn, *tmp_fn;
  1136. FILE *f, *tmp_f;
  1137. char buf[MC_MAXPATHLEN + 100];
  1138. size_t i;
  1139. const size_t len = strlen (filename);
  1140. gboolean src_error = FALSE;
  1141. if (filepos_max_saved_entries == 0)
  1142. filepos_max_saved_entries = mc_config_get_int (mc_main_config, CONFIG_APP_SECTION,
  1143. "filepos_max_saved_entries", 1024);
  1144. fn = g_build_filename (home_dir, MC_USERCONF_DIR, MC_FILEPOS_FILE, NULL);
  1145. if (fn == NULL)
  1146. goto early_error;
  1147. mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
  1148. /* open file */
  1149. f = fopen (fn, "w");
  1150. if (f == NULL)
  1151. goto open_target_error;
  1152. tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
  1153. tmp_f = fopen (tmp_fn, "r");
  1154. if (tmp_f == NULL)
  1155. {
  1156. src_error = TRUE;
  1157. goto open_source_error;
  1158. }
  1159. /* put the new record */
  1160. if (line != 1 || column != 0 || bookmarks != NULL)
  1161. {
  1162. if (fprintf (f, "%s %ld;%ld;%ju", filename, line, column, offset) < 0)
  1163. goto write_position_error;
  1164. if (bookmarks != NULL)
  1165. for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
  1166. if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
  1167. goto write_position_error;
  1168. if (fprintf (f, "\n") < 0)
  1169. goto write_position_error;
  1170. }
  1171. i = 1;
  1172. while (fgets (buf, sizeof (buf), tmp_f) != NULL)
  1173. {
  1174. if (buf[len] == ' ' && strncmp (buf, filename, len) == 0
  1175. && strchr (&buf[len + 1], ' ') == NULL)
  1176. continue;
  1177. fprintf (f, "%s", buf);
  1178. if (++i > filepos_max_saved_entries)
  1179. break;
  1180. }
  1181. write_position_error:
  1182. fclose (tmp_f);
  1183. open_source_error:
  1184. g_free (tmp_fn);
  1185. fclose (f);
  1186. if (src_error)
  1187. mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
  1188. else
  1189. mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
  1190. open_target_error:
  1191. g_free (fn);
  1192. early_error:
  1193. if (bookmarks != NULL)
  1194. g_array_free (bookmarks, TRUE);
  1195. }
  1196. /* --------------------------------------------------------------------------------------------- */
  1197. extern int
  1198. ascii_alpha_to_cntrl (int ch)
  1199. {
  1200. if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
  1201. {
  1202. ch &= 0x1f;
  1203. }
  1204. return ch;
  1205. }
  1206. /* --------------------------------------------------------------------------------------------- */
  1207. const char *
  1208. Q_ (const char *s)
  1209. {
  1210. const char *result, *sep;
  1211. result = _(s);
  1212. sep = strchr (result, '|');
  1213. return (sep != NULL) ? sep + 1 : result;
  1214. }
  1215. /* --------------------------------------------------------------------------------------------- */
  1216. gboolean
  1217. mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
  1218. {
  1219. struct stat stat_buf;
  1220. char *backup_path;
  1221. gboolean ret;
  1222. if (!exist_file (file_name))
  1223. return FALSE;
  1224. backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
  1225. if (backup_path == NULL)
  1226. return FALSE;
  1227. ret = mc_util_write_backup_content (file_name, backup_path);
  1228. if (ret)
  1229. {
  1230. /* Backup file will have same ownership with main file. */
  1231. if (stat (file_name, &stat_buf) == 0)
  1232. chmod (backup_path, stat_buf.st_mode);
  1233. else
  1234. chmod (backup_path, S_IRUSR | S_IWUSR);
  1235. }
  1236. g_free (backup_path);
  1237. return ret;
  1238. }
  1239. /* --------------------------------------------------------------------------------------------- */
  1240. gboolean
  1241. mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
  1242. {
  1243. gboolean ret;
  1244. char *backup_path;
  1245. backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
  1246. if (backup_path == NULL)
  1247. return FALSE;
  1248. ret = mc_util_write_backup_content (backup_path, file_name);
  1249. g_free (backup_path);
  1250. return ret;
  1251. }
  1252. /* --------------------------------------------------------------------------------------------- */
  1253. gboolean
  1254. mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
  1255. {
  1256. char *backup_path;
  1257. backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
  1258. if (backup_path == NULL)
  1259. return FALSE;
  1260. if (exist_file (backup_path))
  1261. mc_unlink (backup_path);
  1262. g_free (backup_path);
  1263. return TRUE;
  1264. }
  1265. /* --------------------------------------------------------------------------------------------- */
  1266. /**
  1267. * partly taken from dcigettext.c, returns "" for default locale
  1268. * value should be freed by calling function g_free()
  1269. */
  1270. char *
  1271. guess_message_value (void)
  1272. {
  1273. static const char *const var[] = {
  1274. /* Setting of LC_ALL overwrites all other. */
  1275. /* Do not use LANGUAGE for check user locale and drowing hints */
  1276. "LC_ALL",
  1277. /* Next comes the name of the desired category. */
  1278. "LC_MESSAGES",
  1279. /* Last possibility is the LANG environment variable. */
  1280. "LANG",
  1281. /* NULL exit loops */
  1282. NULL
  1283. };
  1284. unsigned i = 0;
  1285. const char *locale = NULL;
  1286. while (var[i] != NULL)
  1287. {
  1288. locale = getenv (var[i]);
  1289. if (locale != NULL && locale[0] != '\0')
  1290. break;
  1291. i++;
  1292. }
  1293. if (locale == NULL)
  1294. locale = "";
  1295. return g_strdup (locale);
  1296. }
  1297. /* --------------------------------------------------------------------------------------------- */