PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/libgebr/validate.c

https://code.google.com/p/gebr/
C | 534 lines | 434 code | 75 blank | 25 comment | 123 complexity | 65535489c03b68f46a743df9205efeab MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. /* libgebr - GeBR Library
  2. * Copyright (C) 2007-2009 GeBR core team (http://www.gebrproject.com/)
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include <string.h>
  21. #include <regex.h>
  22. #include "libgebr-gettext.h"
  23. #include <glib/gi18n-lib.h>
  24. #include "validate.h"
  25. #include "geoxml/gebr-geoxml-validate.h"
  26. /*
  27. * Prototypes
  28. */
  29. static GebrValidateCase validate_cases[] = {
  30. /* menu */
  31. {GEBR_VALIDATE_CASE_FILENAME,
  32. GEBR_VALIDATE_CHECK_NOBLK | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_FILEN,
  33. N_("File names must be a valid path.")},
  34. {GEBR_VALIDATE_CASE_TITLE,
  35. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  36. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  37. N_("Titles should not start with spaces or end with punctuation characters.")},
  38. {GEBR_VALIDATE_CASE_DESCRIPTION,
  39. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  40. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  41. N_("Description should be capitalized and have no punctuation characters at the end.")},
  42. {GEBR_VALIDATE_CASE_AUTHOR,
  43. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  44. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  45. N_("Author should be capitalized and have no punctuation characters at the end.")},
  46. {GEBR_VALIDATE_CASE_DATE,
  47. GEBR_VALIDATE_CHECK_EMPTY,
  48. N_("Date should not be empty.")},
  49. {GEBR_VALIDATE_CASE_HELP,
  50. GEBR_VALIDATE_CHECK_EMPTY,
  51. N_("Help should not be empty.")},
  52. {GEBR_VALIDATE_CASE_CATEGORY,
  53. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  54. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  55. N_("Categories should be capitalized and have no punctuation characters at the end.")},
  56. {GEBR_VALIDATE_CASE_EMAIL,
  57. GEBR_VALIDATE_CHECK_EMAIL,
  58. N_("Invalid email address.")},
  59. /* program */
  60. {GEBR_VALIDATE_CASE_PROGRAM_TITLE,
  61. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  62. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  63. N_("Program titles should not have extra spaces.")},
  64. {GEBR_VALIDATE_CASE_PROGRAM_DESCRIPTION,
  65. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  66. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_TABS,
  67. N_("Program description should be capitalized and have no punctuation characters at the end.")},
  68. {GEBR_VALIDATE_CASE_PROGRAM_BINARY,
  69. GEBR_VALIDATE_CHECK_EMPTY,
  70. N_("Binaries should not be empty.")},
  71. {GEBR_VALIDATE_CASE_PROGRAM_VERSION,
  72. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_NOBLK | GEBR_VALIDATE_CHECK_NOPNT
  73. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_TABS,
  74. N_("Program version should be filled in.")},
  75. {GEBR_VALIDATE_CASE_PROGRAM_URL,
  76. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_URL,
  77. N_("Program url should start with a protocol.")},
  78. /* parameter */
  79. {GEBR_VALIDATE_CASE_PARAMETER_LABEL,
  80. GEBR_VALIDATE_CHECK_EMPTY | GEBR_VALIDATE_CHECK_CAPIT | GEBR_VALIDATE_CHECK_NOBLK
  81. | GEBR_VALIDATE_CHECK_MTBLK | GEBR_VALIDATE_CHECK_NOPNT | GEBR_VALIDATE_CHECK_LABEL_HOTKEY
  82. | GEBR_VALIDATE_CHECK_TABS,
  83. N_("Parameter label should be capitalized and have no punctuation characters at the end. Also, be careful with colliding shortcuts.")},
  84. {GEBR_VALIDATE_CASE_PARAMETER_KEYWORD,
  85. GEBR_VALIDATE_CHECK_EMPTY,
  86. N_("Parameter keyword should not be empty.")},
  87. };
  88. /*
  89. * Public functions
  90. */
  91. GebrValidateCase * gebr_validate_get_validate_case(GebrValidateCaseName name)
  92. {
  93. static gint n_elements = G_N_ELEMENTS(validate_cases);
  94. for (int i = 0; i < n_elements; i++)
  95. if (validate_cases[i].name == name)
  96. return &validate_cases[i];
  97. return NULL;
  98. }
  99. const gchar * gebr_validate_case_get_message (GebrValidateCase *validate_case)
  100. {
  101. return _(validate_case->validcase_msg);
  102. }
  103. gint gebr_validate_case_check_value(GebrValidateCase * self, const gchar * value, gboolean * can_fix)
  104. {
  105. gint flags = self->flags;
  106. gint failed = 0;
  107. if (can_fix != NULL)
  108. *can_fix = (strlen(value) == 0 ||
  109. flags & GEBR_VALIDATE_CHECK_EMAIL ||
  110. flags & GEBR_VALIDATE_CHECK_FILEN) ? FALSE : TRUE;
  111. void gebr_validate_case_check_value_aux(const gchar *value)
  112. {
  113. if (flags & GEBR_VALIDATE_CHECK_EMPTY && !gebr_validate_check_is_not_empty(value))
  114. failed |= GEBR_VALIDATE_CHECK_EMPTY;
  115. if (flags & GEBR_VALIDATE_CHECK_CAPIT && !gebr_validate_check_no_lower_case(value))
  116. failed |= GEBR_VALIDATE_CHECK_CAPIT;
  117. if (flags & GEBR_VALIDATE_CHECK_NOBLK && !gebr_validate_check_no_blanks_at_boundaries(value))
  118. failed |= GEBR_VALIDATE_CHECK_NOBLK;
  119. if (flags & GEBR_VALIDATE_CHECK_MTBLK && !gebr_validate_check_no_multiple_blanks(value))
  120. failed |= GEBR_VALIDATE_CHECK_MTBLK;
  121. if (flags & GEBR_VALIDATE_CHECK_NOPNT && !gebr_validate_check_no_punctuation_at_end(value))
  122. failed |= GEBR_VALIDATE_CHECK_NOPNT;
  123. if (flags & GEBR_VALIDATE_CHECK_EMAIL && !gebr_validate_check_is_email(value))
  124. failed |= GEBR_VALIDATE_CHECK_EMAIL;
  125. if (flags & GEBR_VALIDATE_CHECK_FILEN && !gebr_validate_check_menu_filename(value))
  126. failed |= GEBR_VALIDATE_CHECK_FILEN;
  127. if (flags & GEBR_VALIDATE_CHECK_URL && !gebr_validate_check_is_url(value))
  128. failed |= GEBR_VALIDATE_CHECK_URL;
  129. if (flags & GEBR_VALIDATE_CHECK_TABS && !gebr_validate_check_tabs(value))
  130. failed |= GEBR_VALIDATE_CHECK_TABS;
  131. }
  132. if (self->name == GEBR_VALIDATE_CASE_CATEGORY) {
  133. gchar **cats = g_strsplit(value, "|", 0);
  134. for (int i = 0; cats[i] != NULL; ++i)
  135. gebr_validate_case_check_value_aux(cats[i]);
  136. g_strfreev(cats);
  137. } else
  138. gebr_validate_case_check_value_aux(value);
  139. return failed;
  140. }
  141. gchar * gebr_validate_case_fix(GebrValidateCase * self, const gchar * value)
  142. {
  143. gboolean can_fix;
  144. gebr_validate_case_check_value(self, value, &can_fix);
  145. if (!can_fix)
  146. return NULL;
  147. gchar * gebr_validate_case_fix_aux(const gchar *value, gboolean *has_fix)
  148. {
  149. gchar * tmp = NULL;
  150. gchar * fix = g_strdup(value);
  151. *has_fix = FALSE;
  152. if (self->flags & GEBR_VALIDATE_CHECK_CAPIT
  153. && !gebr_validate_check_no_lower_case(fix)) {
  154. if (fix != NULL)
  155. tmp = fix;
  156. fix = gebr_validate_change_first_to_upper(fix);
  157. if (tmp) {
  158. g_free(tmp);
  159. tmp = NULL;
  160. }
  161. *has_fix = TRUE;
  162. }
  163. if (self->flags & GEBR_VALIDATE_CHECK_NOBLK
  164. && !gebr_validate_check_no_blanks_at_boundaries(fix)) {
  165. if (fix != NULL)
  166. tmp = fix;
  167. fix = gebr_validate_change_no_blanks_at_boundaries(fix);
  168. if (tmp) {
  169. g_free(tmp);
  170. tmp = NULL;
  171. }
  172. *has_fix = TRUE;
  173. }
  174. if (self->flags & GEBR_VALIDATE_CHECK_MTBLK
  175. && !gebr_validate_check_no_multiple_blanks(fix)) {
  176. if (fix != NULL)
  177. tmp = fix;
  178. fix = gebr_validate_change_multiple_blanks(fix);
  179. if (tmp) {
  180. g_free(tmp);
  181. tmp = NULL;
  182. }
  183. *has_fix = TRUE;
  184. }
  185. if (self->flags & GEBR_VALIDATE_CHECK_NOPNT
  186. && !gebr_validate_check_no_punctuation_at_end(fix)) {
  187. if (fix != NULL)
  188. tmp = fix;
  189. fix = gebr_validate_change_no_punctuation_at_end(fix);
  190. if (tmp) {
  191. g_free(tmp);
  192. tmp = NULL;
  193. }
  194. *has_fix = TRUE;
  195. }
  196. if (self->flags & GEBR_VALIDATE_CHECK_URL
  197. && !gebr_validate_check_is_url(fix)) {
  198. if (fix != NULL)
  199. tmp = fix;
  200. fix = gebr_validate_change_url(fix);
  201. if (tmp) {
  202. g_free(tmp);
  203. tmp = NULL;
  204. }
  205. *has_fix = TRUE;
  206. }
  207. if (self->flags & GEBR_VALIDATE_CHECK_TABS
  208. && !gebr_validate_check_tabs(fix)) {
  209. if (fix != NULL)
  210. tmp = fix;
  211. fix = gebr_validate_change_tabs(fix);
  212. if (tmp) {
  213. g_free(tmp);
  214. tmp = NULL;
  215. }
  216. *has_fix = TRUE;
  217. }
  218. return fix;
  219. }
  220. gchar * gebr_validate_case_fix_aux_iter(const gchar *value)
  221. {
  222. gchar *tmp;
  223. gboolean has_fix;
  224. gchar *fix = gebr_validate_case_fix_aux (value, &has_fix);
  225. while (has_fix) {
  226. tmp = fix;
  227. fix = gebr_validate_case_fix_aux (fix, &has_fix);
  228. g_free (tmp);
  229. }
  230. return fix;
  231. }
  232. if (self->name == GEBR_VALIDATE_CASE_CATEGORY) {
  233. GString *fix = g_string_new("");
  234. gchar **cats = g_strsplit(value, "|", 0);
  235. for (int i = 0; cats[i] != NULL; i++) {
  236. gchar *ifix = gebr_validate_case_fix_aux_iter(cats[i]);
  237. g_string_append_printf(fix, "%s%s", ifix != NULL ? ifix : cats[i], cats[i+1] != NULL ? "|" : "");
  238. if (ifix != NULL)
  239. g_free(ifix);
  240. }
  241. g_strfreev(cats);
  242. gchar *ret = fix->str;
  243. g_string_free(fix, FALSE);
  244. return ret;
  245. } else
  246. return gebr_validate_case_fix_aux_iter(value);
  247. }
  248. gchar *gebr_validate_case_automatic_fixes_msg(GebrValidateCase *self, const gchar * value, gboolean * can_fix)
  249. {
  250. gint failed = gebr_validate_case_check_value(self, value, can_fix);
  251. if (!(*can_fix))
  252. return g_strdup(_("<b>No automatic fix available</b>"));
  253. GString *msg = g_string_new(_("<b>Click on the icon to fix:</b>"));
  254. if (failed & GEBR_VALIDATE_CHECK_CAPIT)
  255. g_string_append(msg, _("\n - Capitalize first letter"));
  256. if (failed & GEBR_VALIDATE_CHECK_NOBLK)
  257. g_string_append(msg, _("\n - Remove spaces at the beginning/end"));
  258. if (failed & GEBR_VALIDATE_CHECK_MTBLK)
  259. g_string_append(msg, _("\n - Remove multiples spaces"));
  260. if (failed & GEBR_VALIDATE_CHECK_NOPNT)
  261. g_string_append(msg, _("\n - Remove final punctuation character"));
  262. if (failed & GEBR_VALIDATE_CHECK_URL)
  263. g_string_append(msg, _("\n - Add URL scheme"));
  264. if (failed & GEBR_VALIDATE_CHECK_TABS)
  265. g_string_append(msg, _("\n - Replace tabs by space"));
  266. gchar *ret = msg->str;
  267. g_string_free(msg, FALSE);
  268. return ret;
  269. }
  270. gchar *gebr_validate_flags_failed_msg(gint failed_flags)
  271. {
  272. if (!failed_flags)
  273. return NULL;
  274. GString *msg = g_string_new(_("<b>Error(s) found:</b>"));
  275. if (failed_flags & GEBR_VALIDATE_CHECK_EMPTY)
  276. g_string_append(msg, _("\n - The field is not filled in"));
  277. if (failed_flags & GEBR_VALIDATE_CHECK_CAPIT)
  278. g_string_append(msg, _("\n - First letter should be capitalized"));
  279. if (failed_flags & GEBR_VALIDATE_CHECK_NOBLK)
  280. g_string_append(msg, _("\n - There are spaces at the beginning/end"));
  281. if (failed_flags & GEBR_VALIDATE_CHECK_MTBLK)
  282. g_string_append(msg, _("\n - There are multiples spaces"));
  283. if (failed_flags & GEBR_VALIDATE_CHECK_NOPNT)
  284. g_string_append(msg, _("\n - This field should not have a final punctuation"));
  285. if (failed_flags & GEBR_VALIDATE_CHECK_EMAIL)
  286. g_string_append(msg, _("\n - Invalid email address"));
  287. if (failed_flags & GEBR_VALIDATE_CHECK_FILEN)
  288. g_string_append(msg, _("\n - Invalid menu filename"));
  289. if (failed_flags & GEBR_VALIDATE_CHECK_LABEL_HOTKEY)
  290. g_string_append(msg, _("\n - Duplicated hotkey"));
  291. if (failed_flags & GEBR_VALIDATE_CHECK_URL)
  292. g_string_append(msg, _("\n - URL scheme is missing"));
  293. if (failed_flags & GEBR_VALIDATE_CHECK_TABS)
  294. g_string_append(msg, _("\n - There are tabs"));
  295. gchar *ret = msg->str;
  296. g_string_free(msg, FALSE);
  297. return ret;
  298. }
  299. gboolean gebr_validate_check_is_not_empty(const gchar * str)
  300. {
  301. return (strlen(str) ? TRUE : FALSE);
  302. }
  303. gboolean gebr_validate_check_no_lower_case(const gchar * sentence)
  304. {
  305. if (!gebr_validate_check_is_not_empty(sentence))
  306. return TRUE;
  307. if (g_unichar_islower(g_utf8_get_char_validated(sentence, -1)))
  308. return FALSE;
  309. return TRUE;
  310. }
  311. gchar * gebr_validate_change_first_to_upper(const gchar * sentence)
  312. {
  313. gchar char_utf8[6];
  314. gchar * uppercase;
  315. gint length = g_unichar_to_utf8(g_utf8_get_char(sentence), char_utf8);
  316. uppercase = g_utf8_strup(char_utf8, length);
  317. return g_strjoin(NULL, uppercase, sentence+length, NULL);
  318. }
  319. gboolean gebr_validate_check_tabs(const gchar * str)
  320. {
  321. regex_t pattern;
  322. regcomp(&pattern, "\t\t*", REG_NOSUB);
  323. return (regexec(&pattern, str, 0, 0, 0) ? TRUE : FALSE);
  324. }
  325. gchar * gebr_validate_change_tabs(const gchar * sentence)
  326. {
  327. #if GLIB_CHECK_VERSION(2,14,0)
  328. GRegex *regex;
  329. GError *error = NULL;
  330. regex = g_regex_new("\t\t*", 0, 0, &error);
  331. if (error != NULL) {
  332. g_warning("%s:%d %s", __FILE__, __LINE__, error->message);
  333. g_error_free(error);
  334. if (regex)
  335. g_regex_unref(regex);
  336. return NULL;
  337. }
  338. gchar *ret = g_regex_replace(regex, sentence, -1, 0, " ", 0, NULL);
  339. g_regex_unref(regex);
  340. return ret;
  341. #else
  342. return NULL;
  343. #endif
  344. }
  345. gboolean gebr_validate_check_no_multiple_blanks(const gchar * str)
  346. {
  347. regex_t pattern;
  348. regcomp(&pattern, " *", REG_NOSUB);
  349. return (regexec(&pattern, str, 0, 0, 0) ? TRUE : FALSE);
  350. }
  351. gchar * gebr_validate_change_multiple_blanks(const gchar * sentence)
  352. {
  353. #if GLIB_CHECK_VERSION(2,14,0)
  354. GRegex *regex;
  355. GError *error = NULL;
  356. regex = g_regex_new("[[:space:]]{2,}", 0, 0, &error);
  357. if (error != NULL) {
  358. g_warning("%s:%d %s", __FILE__, __LINE__, error->message);
  359. g_error_free(error);
  360. if (regex)
  361. g_regex_unref(regex);
  362. return NULL;
  363. }
  364. gchar *ret = g_regex_replace(regex, sentence, -1, 0, " ", 0, NULL);
  365. g_regex_unref(regex);
  366. return ret;
  367. #else
  368. return NULL;
  369. #endif
  370. }
  371. gboolean gebr_validate_check_no_blanks_at_boundaries(const gchar * str)
  372. {
  373. int n = strlen(str);
  374. if (n == 0)
  375. return TRUE;
  376. if (str[0] == ' ' || str[0] == '\t' || str[n - 1] == ' ' || str[n - 1] == '\t')
  377. return FALSE;
  378. return TRUE;
  379. }
  380. gchar * gebr_validate_change_no_blanks_at_boundaries(const gchar * sentence)
  381. {
  382. #if GLIB_CHECK_VERSION(2,14,0)
  383. GRegex *regex;
  384. GError *error = NULL;
  385. regex = g_regex_new("^[[:space:]]+|[[:space:]]+$", 0, 0, NULL);
  386. if (error != NULL) {
  387. g_warning("%s:%d %s", __FILE__, __LINE__, error->message);
  388. g_error_free(error);
  389. if (regex)
  390. g_regex_unref(regex);
  391. return NULL;
  392. }
  393. gchar *ret = g_regex_replace(regex, sentence, -1, 0, "", 0, NULL);
  394. g_regex_unref(regex);
  395. return ret;
  396. #else
  397. return NULL;
  398. #endif
  399. }
  400. gboolean gebr_validate_check_no_punctuation_at_end(const gchar * str)
  401. {
  402. int n = strlen(str);
  403. if (n == 0)
  404. return TRUE;
  405. if (str[n - 1] != ')' && g_ascii_ispunct(str[n - 1]))
  406. return FALSE;
  407. return TRUE;
  408. }
  409. gchar * gebr_validate_change_no_punctuation_at_end(const gchar * sentence)
  410. {
  411. gchar *str = g_strdup(sentence);
  412. if (str) {
  413. int n = strlen(str) - 1;
  414. while(str[n] != ')' && g_ascii_ispunct(str[n]))
  415. n--;
  416. str[n + 1] = '\0';
  417. }
  418. return str;
  419. }
  420. gboolean gebr_validate_check_menu_filename(const gchar * str)
  421. {
  422. gchar *base;
  423. base = g_path_get_basename(str);
  424. if (strcmp(base, str)) {
  425. g_free(base);
  426. return FALSE;
  427. }
  428. g_free(base);
  429. if (!g_str_has_suffix(str, ".mnu"))
  430. return FALSE;
  431. return TRUE;
  432. }
  433. gboolean gebr_validate_check_is_email(const gchar * str)
  434. {
  435. regex_t pattern;
  436. regcomp(&pattern, "^[a-z0-9_.-][a-z0-9_.-]*@[a-z0-9.-]*\\.[a-z0-9-][a-z0-9-]*$", REG_NOSUB | REG_ICASE);
  437. return (!regexec(&pattern, str, 0, 0, 0) ? TRUE : FALSE);
  438. }
  439. gboolean gebr_validate_check_is_url(const gchar * str)
  440. {
  441. return (g_str_has_prefix(str, "http://") ||
  442. g_str_has_prefix(str, "mailto:") ||
  443. g_str_has_prefix(str, "file://") ||
  444. g_str_has_prefix(str, "ftp://") );
  445. }
  446. gchar * gebr_validate_change_url(const gchar * sentence)
  447. {
  448. gchar *str;
  449. if (gebr_validate_check_is_email(sentence))
  450. return g_strconcat("mailto:", sentence, NULL);
  451. else if (g_str_has_prefix(sentence, "ftp."))
  452. return g_strconcat("ftp://", sentence, NULL);
  453. else if (g_str_has_prefix(sentence, "/"))
  454. return g_strconcat("file://", sentence, NULL);
  455. else
  456. return g_strconcat("http://", sentence, NULL);
  457. str = g_strdup(sentence);
  458. return str;
  459. }