GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
reg_entries.c
Go to the documentation of this file.
1 
2 /***************************************************************************
3  * reg_entries.c
4  *
5  * Fri May 13 11:35:33 2005
6  * Copyright 2005 User
7  * Email
8  ****************************************************************************/
9 
10 /*
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 #include <dirent.h>
27 #include "globals.h"
28 
30 
31 
32  /*
33  Returns 1, if the string is a submenu item, 0 otherwise.
34  Very primitive
35  */
36 int is_submenu(char *item)
37 {
38  if (strchr(item, '[') == NULL) {
39  return (0);
40  }
41  if (strrchr(item, ']') == NULL) {
42  return (0);
43  }
44  if (strchr(item, '[') > strrchr(item, ']')) {
45  return (0);
46  }
47  return (1);
48 }
49 
50 
51 /*
52  If "Extensions" menu does not yet exist, it will be created immediately
53  to the left of the "Help" menu in GIS Manager's main menu bar.
54  Returns the line nr after which the "Extension" menu entries should be
55  inserted.
56  */
57 int check_ext_menu(char **tcl_lines)
58 {
59  int idx;
60 
61  /* check if "Extensions" menu exists */
62  idx = find_pos("\"&Xtns\" all options 1", tcl_lines, 0);
63  if (idx == -1) { /* does not exist: create a new one */
64  idx = find_pos("\"&Help\" all options", tcl_lines, 0);
65  if (idx == -1) { /* Help menu does not exist: place at far right */
66  idx = find_pos("}]", tcl_lines, 0);
67  if (idx == -1) {
69  "could not parse 'menu.tcl'.\n");
70  }
71  insert_str(" \"&Xtns\" all options 1 {\n", idx, tcl_lines);
72  idx++;
73  insert_str(" }\n", idx, tcl_lines);
74  return (idx);
75  }
76  insert_str(" \"&Xtns\" all options 1 {\n", idx, tcl_lines);
77  idx++;
78  insert_str(" }\n", idx, tcl_lines);
79  }
80  return (idx);
81 }
82 
83 
84  /*
85  Creates a new submenu for this extension under "Extensions" in GIS Managers
86  main menu bar.
87  Returns line no. of submenu, after which additional entries should be appended
88  to menu.tcl.
89  */
90 int new_submenu(char *pkg_short_name, char *menu, char **tcl_lines)
91 {
92  char tmp[MAXSTR];
93  char tmp2[MAXSTR];
94  char searchstr[MAXSTR];
95  int idx, idx2;
96  int insert_here;
97  int last;
98  char *first_quote;
99  char *second_quote;
100  int len;
101  int terminator;
102 
103  /* Store the position of the "Extensions" entry and start looking for submenu from there */
104  idx = find_pos("\"&Xtns\" all options", tcl_lines, 0);
105  last = find_pos("\" all options", tcl_lines, idx + 1) - 1; /* find end of "Extensions" menu */
106  if (last == -1) {
107  last = find_pos("}]", tcl_lines, 0); /* end of menu.tcl */
108  }
109 
110  /* check if the line is a valid submenu specifier */
111  if (!is_submenu(menu)) {
113  ("first line not a submenu specifier in 'entries-gisman'.\n");
114  return (-1);
115  }
116  else {
117  /* check if a submenu with this name does already exist */
118  len = (strrchr(menu, ']') - strchr(menu, '[')) / sizeof(char);
119  strncpy(tmp, strchr(menu, '[') + sizeof(char), len);
120  tmp[len - 1] = '\0'; /* get rid of [] */
121  sprintf(searchstr, "{cascad \"%s\"", tmp); /* this is what we need to look for */
122 
123  idx2 = find_pos(searchstr, tcl_lines, idx);
124  if ((idx2 != -1) && (idx2 < last)) {
125  print_warning("submenu '%s' exists in GIS Manager's Xtns menu.\n",
126  tmp);
127  return (-1);
128  }
129 
130  /* ELSE: create a new submenu in the right place */
131  insert_here = idx + 1; /* by default: place submenu in first line after "Extensions" menu */
132  idx2 = find_pos("{cascad ", tcl_lines, idx); /* go through all submenus in "Extensions" */
133  while ((idx2 != -1) && (idx2 < last)) {
134  /* check for alphabetical order */
135  first_quote = strchr(tcl_lines[idx2], '\"'); /* get name of submenu w/o quotation marks */
136  second_quote = strchr(first_quote + sizeof(char), '\"');
137  len = (second_quote - first_quote) / sizeof(char);
138  strncpy(tmp2, first_quote + sizeof(char), len);
139  tmp2[len - 1] = '\0'; /* get rid of "" */
140  if (strcmp(tmp, tmp2) < 0) {
141  insert_here = idx2;
142  break;
143  }
144  idx++;
145  idx2 = find_pos("{cascad ", tcl_lines, idx);
146  }
147 
148  /* create new submenu and return line no in menu.tcl for insertion of entries */
149  sprintf(tmp, " \t\t\t%s {} \"\" 1 {\n", searchstr);
150  insert_str(tmp, insert_here, tcl_lines);
151  insert_str(" \t\t\t}}\n", insert_here + 1, tcl_lines);
152 
153  /* create an uninstall entry in menu.tcl */
154  terminator = find_pos("}]", tcl_lines, 0);
155  /* this is just a comment that tells the uninstall function which submenu to remove */
156  sprintf(tmp, "#(DO_NOT_REMOVE_THIS_COMMENT) <%s> %s {} \"\" 1 {\n",
157  pkg_short_name, searchstr);
158  insert_str(tmp, terminator + 1, tcl_lines);
159 
160  /* return next line for insertion of menu entries and commands! */
161  return (insert_here + 1);
162  }
163 
164  return (-1);
165 }
166 
167 
168 /*
169  Inserts a new menu entry into the extension's own submenu under "Extensions".
170  Returns the line number in menu.tcl after which the next entry should be
171  inserted.
172  */
173 int new_item(char *item, char *menu, char **tcl_lines, int line_no)
174 {
175  char *token;
176  int num_tokens;
177  char entry[MAXSTR];
178  char command[MAXSTR];
179  char tmp[MAXSTR];
180 
181 
182  /* remove dangling white spaces and EOL chars */
183  chop(item);
184 
185  token = strtok(item, ";");
186  if (token == NULL) {
187  print_warning("invalid token in 'entries-gisman'.\n");
188  return (-1);
189  }
190 
191  strcpy(entry, token); /* get menu entry string */
192 
193  num_tokens = 0;
194  while (token != NULL) {
195  token = strtok(NULL, ";");
196  if (token != NULL) {
197  strcpy(command, token); /* get command string */
198  }
199  num_tokens++;
200  }
201 
202  if (num_tokens > 2) {
203  print_warning("invalid number of tokens (%i) in 'entries-gisman'.\n",
204  num_tokens);
205  return (-1);
206  }
207 
208  /* just a separator or a 'real' menu entry? */
209  if ((!strcmp(entry, "-")) && (!strcmp(entry, "-"))) {
210  sprintf(tmp, " \t\t\t {separator}\n");
211  }
212  else {
213  sprintf(tmp, " \t\t\t {command \"%s\" {} \"%s\" {} -command {%s }}\n",
214  entry, command, command);
215  }
216  insert_str(tmp, line_no, tcl_lines);
217 
218  /* return line no. for next entry */
219  line_no++;
220  return (line_no);
221 }
222 
223 
224  /*
225  Checks if there are any entries in entries-gisman.
226  Reads GISBASE/etc/dm/menu.tcl into an array of strings.
227  Adds a new item "Extensions" to the menu bar, if it is missing.
228  Adds new submenus and menu items to the GIS manager, as stated in entries-gisman
229  Writes the new menu structure to a temporary file which will then be installed
230  using the 'su' function.
231  */
232 void register_entries_gisman(char *pkg_short_name, char *gisbase)
233 {
234 
235  char file[MAXSTR];
236  char str[MAXSTR];
237  char menu[MAXSTR];
238  int len;
239  char **line;
240  int n_entries, n_lines, i;
241  int n_lines_org, n_lines_new;
242  int line_no;
243  FILE *f_gisman, *f_in, *f_out;
244 
245  /* check if entries-gisman exists and is readable */
246  sprintf(file, "../entries-gisman");
247  f_gisman = fopen(file, "r");
248  if (f_gisman == NULL) {
249  if (errno == ENOENT) {
250  /* file does not exist */
251  return;
252  }
253  else {
254  /* sth. strange happened */
255  fclose(f_gisman);
257  "checking for file '%s': %s\n", file,
258  strerror(errno));
259  }
260  }
261 
262  /* check if menu.tcl exists and is readable */
263  sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
264  f_in = fopen(file, "r");
265  if (f_in == NULL) {
266  if (errno == ENOENT) {
267  /* file does not exist */
268  return;
269  }
270  else {
271  /* sth. strange happened */
272  fclose(f_in);
274  "checking for file '%s': %s\n", file,
275  strerror(errno));
276  }
277  }
278 
279  /* create a temporary menu.tcl file for write access */
280  /* TODO: Do not hardcode temp paths */
281  strcpy(TMP_GISMAN, "/tmp/grass.extensions.db.XXXXXX"); /* TMP_GISMAN is a global variable */
282  mkstemp(TMP_GISMAN);
283 
284  f_out = fopen(TMP_GISMAN, "w+");
285  if (f_out == NULL) {
287  "could not create temp file '%s': %s\n \
288  Make sure that directory /tmp exists on your system and you have write permission.\n", TMP_GISMAN, strerror(errno));
289  }
290  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
291 
292  /* everything fine: create a shell command to install gisman-entries and modified menu.tcl */
293  /* this also creates a backup-copy of menu.tcl */
294  if (VERBOSE) {
295  sprintf(str,
296  "mkdir --verbose %s/etc/dm/gem-entries ; cp -vf ../entries-gisman %s/etc/dm/gem-entries/%s ; \
297  cp -vf %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak ; \
298  cp -vf %s %s/etc/dm/menu.tcl ; chmod -v a+r %s/etc/dm/menu.tcl ;",
299  gisbase, gisbase, pkg_short_name, gisbase, gisbase, TMP_GISMAN, gisbase, gisbase);
300  }
301  else {
302  sprintf(str,
303  "mkdir %s/etc/dm/gem-entries &> %s ; cp -f ../entries-gisman %s/etc/dm/gem-entries/%s &> %s ; \
304  cp -f %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak &> %s ; \
305  cp -f %s %s/etc/dm/menu.tcl &> %s ; chmod a+r %s/etc/dm/menu.tcl &> %s ;",
306  gisbase, TMP_NULL, gisbase, pkg_short_name, TMP_NULL, gisbase, gisbase, TMP_NULL, TMP_GISMAN, gisbase, TMP_NULL, gisbase, TMP_NULL);
307  }
308  strcpy(GISMAN_CMD, str);
309 
310  /* count number of lines in entries-gisman */
311  n_entries = 0;
312  while (fgets(str, MAXSTR, f_gisman) != NULL) {
313  n_entries++;
314  }
315  if (n_entries == 0) {
316  return;
317  }
318  rewind(f_gisman);
319 
320  /* count number of lines in menu.tcl */
321  n_lines = 0;
322  while (fgets(str, MAXSTR, f_in) != NULL) {
323  n_lines++;
324  }
325  if (n_lines == 0) {
326  return;
327  }
328  n_lines_org = n_lines;
329  rewind(f_in);
330 
331  /* create an array large enough to hold all lines in menu.tcl */
332  /* plus the entries that are to be added from entries-gisman */
333  /* plus one NULL terminator */
334  /* and copy all lines from menu.tcl into this */
335  line = (char **)calloc(n_lines + (n_entries * 2) + 6, sizeof(char *));
336  for (i = 0; i < (n_lines + (n_entries * 2) + 6); i++) {
337  line[i] = NULL;
338  }
339  i = 0;
340  while (fgets(str, MAXSTR, f_in) != NULL) {
341  line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
342  strcpy(line[i], str);
343  i++;
344  }
345 
346  check_ext_menu(line); /* create "Extensions" menu if necessary */
347 
348  /* read all lines from entries-gisman and add to menus */
349  i = 1;
350  while (nc_fgets_nb(str, MAXSTR, f_gisman) != NULL) {
351  if (i == 1) {
352  /* store name of menu item */
353  len = (strrchr(str, ']') - strchr(str, '[')) / sizeof(char);
354  strncpy(menu, strchr(str, '[') + sizeof(char), len);
355  menu[len - 1] = '\0'; /* get rid of [] */
356  line_no = new_submenu(pkg_short_name, str, line);
357  if (line_no < 0) {
358  print_warning("no GIS Manager menu entries created.\n");
359  break;
360  }
361  i++;
362  }
363  else {
364  line_no = new_item(str, menu, line, line_no);
365  if (line_no < 0) {
366  print_warning("error creating GIS Manager menu entries.\n");
367  break;
368  }
369  i++;
370  }
371  }
372 
373  /* write output to tmpfile */
374  i = 0;
375  while (line[i] != NULL) {
376  fprintf(f_out, line[i]);
377  i++;
378  }
379  fflush(f_out);
380 
381  /* check for accidental corruption of menu.tcl: if tmpfile has less lines than installed
382  menu.tcl, we did sth. wrong and should leave the orginal file untouched! */
383  rewind(f_out);
384  n_lines_new = 0;
385  while (fgets(str, MAXSTR, f_out) != NULL) {
386  n_lines_new++;
387  }
388  if ((n_lines_new == 0) || (n_lines_new < n_lines_org)) {
390  ("file truncation detected. Retaining orginal file 'menu.tcl'.\n");
391  strcpy(GISMAN_CMD, "");
392  }
393 
394  /* close files */
395  fclose(f_in);
396  fclose(f_gisman);
397  fclose(f_out);
398 
399  /* free memory */
400  for (i = 0; i < (n_lines + (n_entries * 2) + 6); i++) {
401  free(line[i]);
402  }
403  free(line);
404 }
405 
406 
407 /*
408  This version is for Michael Barton's new version of the GIS Manager (gis.m)
409  It is much simpler and more flexible, because gis.m can build menus
410  from files at runtime.
411  All we have to do is make sure there is a folder 'Xtns' in $GISBASE/etc/gm
412  and we copy 'entries-gisman2' (if provided) into that folder using a
413  filename 'extension name'.gem!
414  */
415 void register_entries_gisman2(char *pkg_short_name, char *gisbase)
416 {
417  char file[MAXSTR];
418  FILE *f_gisman2;
419  char str[MAXSTR];
420 
421  /* check if entries-gisman2 exists and is readable */
422  sprintf(file, "../entries-gisman2");
423  f_gisman2 = fopen(file, "r");
424  if (f_gisman2 == NULL) {
425  if (errno == ENOENT) {
426  /* file does not exist */
427  return;
428  }
429  else {
430  /* sth. strange happened */
431  fclose(f_gisman2);
433  "checking for file '%s': %s\n", file,
434  strerror(errno));
435  }
436  }
437 
438  /* let's just blindly create an 'Xtns' dir: if it exists already: no problem */
439  /* and then copy file into it! */
440  if (VERBOSE) {
441  sprintf(str,
442  "mkdir --verbose -p %s/etc/gm/Xtns ; cp -fv ../entries-gisman2 %s/etc/gm/Xtns/%s.gem ; ",
443  gisbase, gisbase, pkg_short_name);
444  }
445  else {
446  sprintf(str,
447  "mkdir -p %s/etc/gm/Xtns ; cp -f ../entries-gisman2 %s/etc/gm/Xtns/%s.gem ; ",
448  gisbase, gisbase, pkg_short_name);
449  }
450  strcpy(GISMAN2_CMD, str);
451 }
452 
453 
454 /*
455  Checks for a comment left by the new_submenu () function in menu.tcl.
456  If it exists, the submenu specified in that comment will be removed along
457  with all its entries.
458  Returns -1 on failure, number of removed entries otherwise.
459  If no more submenu entries exist, this will also remove the "Xtns" menu.
460  */
461 int deregister_entries_gisman(char *pkg_short_name, char *gisbase)
462 {
463  char file[MAXSTR];
464  char str[MAXSTR];
465  char tmp[MAXSTR];
466  char **line;
467  int n_lines, i;
468  int n_lines_org, n_lines_new;
469  FILE *f_in, *f_out;
470  int pos;
471  int start, end;
472  int start_sub, end_sub;
473  char *lq, *rq;
474  int num_removed;
475 
476  /* check if menu.tcl exists and is readable */
477  sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
478  f_in = fopen(file, "r");
479  if (f_in == NULL) {
480  if (errno == ENOENT) {
481  /* file does not exist */
482  return (0);
483  }
484  else {
485  /* sth. strange happened */
486  fclose(f_in);
488  "checking for file '%s': %s\n", file,
489  strerror(errno));
490  }
491  }
492 
493  /* create a temporary menu.tcl file for write access */
494  /* TODO: Do not hardcode temp paths */
495  strcpy(TMP_GISMAN, "/tmp/grass.extensions.db.XXXXXX"); /* TMP_GISMAN is a global variable */
496  mkstemp(TMP_GISMAN);
497 
498  f_out = fopen(TMP_GISMAN, "w+");
499  if (f_out == NULL) {
501  "could not create temp file '%s': %s\n \
502  Make sure that directory /tmp exists on your system and you have write permission.\n", TMP_GISMAN, strerror(errno));
503  }
504  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
505 
506  /* everything fine: create a shell command to copy modified menu.tcl on uninstall */
507  if (VERBOSE) {
508  sprintf(str, "cp -vf %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak ; \
509  cp -vf %s %s/etc/dm/menu.tcl ; chmod -v a+r %s/etc/dm/menu.tcl ;", gisbase, gisbase, TMP_GISMAN, gisbase, gisbase);
510  }
511  else {
512  sprintf(str,
513  "cp -f %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak &> %s ; \
514  cp -f %s %s/etc/dm/menu.tcl &> %s ; chmod a+r %s/etc/dm/menu.tcl &> %s ;", gisbase, gisbase, TMP_NULL, TMP_GISMAN, gisbase, TMP_NULL, gisbase, TMP_NULL);
515  }
516  strcpy(GISMAN_CMD, str);
517 
518 
519  /* count number of lines in menu.tcl */
520  n_lines = 0;
521  while (fgets(str, MAXSTR, f_in) != NULL) {
522  n_lines++;
523  }
524  if (n_lines == 0) {
525  return (-1);
526  }
527  rewind(f_in);
528  n_lines_org = n_lines;
529 
530  /* create an array large enough to hold all lines in menu.tcl */
531  /* plus one NULL terminator */
532  /* and copy all lines from menu.tcl into this */
533  line = (char **)calloc(n_lines + 1, sizeof(char *));
534  for (i = 0; i < n_lines + 1; i++) {
535  line[i] = NULL;
536  }
537  i = 0;
538  while (fgets(str, MAXSTR, f_in) != NULL) {
539  line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
540  strcpy(line[i], str);
541  i++;
542  }
543 
544  /* search for uninstall comment */
545  sprintf(str, "#(DO_NOT_REMOVE_THIS_COMMENT) <%s> {cascad",
546  pkg_short_name);
547  pos = find_pos(str, line, 0);
548  if (pos == -1) {
550  ("could not find uninstall information in 'menu.tcl'.\n");
551  return (-1);
552  }
553 
554  /* copy name of submenu to search for */
555  lq = strchr(line[pos], '\"');
556  lq++;
557  rq = strchr(lq, '\"');
558  strcpy(tmp, lq);
559  tmp[(rq - lq) / sizeof(char)] = '\0';
560 
561  /* now find "Xtns" menu start and end */
562  start = find_pos("\"&Xtns\" all options 1", line, 0);
563  end = find_pos("\" all options", line, start + 1) - 1;
564  if (end == -1) {
565  end = find_pos("}]", line, 0); /* end of menu.tcl */
566  }
567 
568  if (start == -1) {
569  print_warning("menu 'Xtns' does not exist.\n");
570  return (-1);
571  }
572 
573  /* now find our submenu and set the search range to it */
574  sprintf(str, "{cascad \"%s\"", tmp);
575  start_sub = find_pos(str, line, start);
576  if ((start_sub == -1) || (start_sub > end)) {
577  print_warning("could not find submenu entry '%s' in 'menu.tcl'.\n",
578  tmp);
579  return (-1);
580  }
581  end_sub = find_pos(" \t\t\t}}", line, start_sub);
582  if ((end_sub == -1) || (end_sub > end)) {
584  ("could not find end of submenu entry '%s' in 'menu.tcl'.\n",
585  tmp);
586  return (-1);
587  }
588 
589  num_removed = 0;
590 
591  /* now kill every line in between start and end! */
592  for (i = 0; i < ((end_sub - start_sub) + 1); i++) {
593  delete_str(start_sub, line);
594  num_removed++;
595  }
596 
597  /* now kill the uninstall comment */
598  sprintf(str, "#(DO_NOT_REMOVE_THIS_COMMENT) <%s> {cascad",
599  pkg_short_name);
600  pos = find_pos(str, line, 0);
601  delete_str(pos, line);
602  num_removed++;
603 
604  /* check if there are any submenus left in "Xtns" and if not: remove Xtns menu */
605  start = find_pos("\"&Xtns\" all options 1", line, 0);
606  end = find_pos("\" all options", line, start + 1) - 1;
607  if (end - start < 3) {
608  for (i = 0; i < ((end - start) + 1); i++) {
609  delete_str(start, line);
610  num_removed++;
611  }
612  }
613 
614  /* write output to tmpfile */
615  i = 0;
616  while (line[i] != NULL) {
617  fprintf(f_out, line[i]);
618  i++;
619  }
620  fflush(f_out);
621 
622  /* check for accidental corruption of menu.tcl: if tmpfile is empty (=0 lines),
623  we did sth. wrong and should leave the orginal file untouched! */
624  rewind(f_out);
625  n_lines_new = 0;
626  while (fgets(str, MAXSTR, f_out) != NULL) {
627  n_lines_new++;
628  }
629  if ((n_lines_new == 0)) {
631  ("file truncation detected. Retaining orginal file 'menu.tcl'.\n");
632  strcpy(GISMAN_CMD, "");
633  }
634 
635  /* close files */
636  fclose(f_in);
637  fclose(f_out);
638 
639  /* free memory */
640  for (i = 0; i < n_lines + 1; i++) {
641  free(line[i]);
642  }
643  free(line);
644 
645  return (num_removed);
646 }
647 
648 
649 /*
650  This version is for Michael Barton's new GIS Manager.
651  In this case, all we have to do is delete the .gem file!
652  */
653 void deregister_entries_gisman2(char *pkg_short_name, char *gisbase)
654 {
655  char file[MAXSTR];
656  FILE *f_gisman2;
657  char str[MAXSTR];
658 
659  /* check if entries-gisman2 exists and is readable */
660  sprintf(file, "%s/etc/gm/Xtns/%s.gem", gisbase, pkg_short_name);
661  f_gisman2 = fopen(file, "r");
662  if (f_gisman2 == NULL) {
663  if (errno == ENOENT) {
664  /* file does not exist */
665  return;
666  }
667  else {
668  /* sth. strange happened */
669  fclose(f_gisman2);
671  "checking for file '%s': %s\n", file,
672  strerror(errno));
673  }
674  }
675 
676  if (VERBOSE) {
677  sprintf(str, "rm -vf %s/etc/gm/Xtns/%s.gem ; ",
678  gisbase, pkg_short_name);
679  }
680  else {
681  sprintf(str, "rm -f %s/etc/gm/Xtns/%s.gem ; ",
682  gisbase, pkg_short_name);
683 
684  }
685  strcpy(GISMAN_CMD, str);
686 }
687 
688 
689 /*
690  Returns number of restored entries
691  */
693 {
694  char str[MAXSTR];
695  char menu[MAXSTR];
696  char file[MAXSTR];
697  char dir[MAXSTR];
698  char pkg_short_name[MAXSTR];
699  int len;
700  char **line;
701  int n_entries, n_lines, i;
702  int line_no;
703  FILE *f_gisman, *f_in, *f_out;
704  DIR *dirp;
705  struct dirent *ep;
706  int num_restored;
707  int n_files;
708 
709  /* check if menu.tcl exists and is readable */
710  sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
711  f_in = fopen(file, "r");
712  if (f_in == NULL) {
713  if (errno == ENOENT) {
714  /* file does not exist */
715  return (0);
716  }
717  else {
718  /* sth. strange happened */
719  fclose(f_in);
721  "checking for file '%s': %s\n", file,
722  strerror(errno));
723  }
724  }
725 
726  /* create a temporary menu.tcl file for write access */
727  /* TODO: Do not hardcode temp paths */
728  strcpy(TMP_GISMAN, "/tmp/grass.extensions.db.XXXXXX"); /* TMP_GISMAN is a global variable */
729  mkstemp(TMP_GISMAN);
730 
731  f_out = fopen(TMP_GISMAN, "w+");
732  if (f_out == NULL) {
734  "could not create temp file '%s': %s\n \
735  Make sure that directory /tmp exists on your system and you have write permission.\n", TMP_GISMAN, strerror(errno));
736  }
737  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
738 
739  /* everything fine: create a shell command to copy modified menu.tcl on uninstall */
740  if (VERBOSE) {
741  sprintf(str, "cp -vf %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak ; \
742  cp -vf %s %s/etc/dm/menu.tcl ; chmod -v a+r %s/etc/dm/menu.tcl ;", gisbase, gisbase, TMP_GISMAN, gisbase, gisbase);
743  }
744  else {
745  sprintf(str,
746  "cp -f %s/etc/dm/menu.tcl %s/etc/dm/menu.tcl.gem.bak &> %s ; \
747  cp -f %s %s/etc/dm/menu.tcl &> %s ; chmod a+r %s/etc/dm/menu.tcl &> %s ;", gisbase, gisbase, TMP_NULL, TMP_GISMAN, gisbase, TMP_NULL, gisbase, TMP_NULL);
748  }
749  strcpy(GISMAN_CMD, str);
750 
751  /* allocate a pointer to the directory structure */
752  sprintf(dir, "%s/etc/dm/gem-entries", gisbase);
753  dirp = opendir(dir);
754  if (dirp == NULL) {
755  /* directory does not exist or is not accessible */
756  return (0);
757  }
758 
759  /* PASS 1 */
760  /* open all files in gem-entries and count the number of lines each has */
761  n_entries = 0;
762  n_files = 0;
763  while ((ep = readdir(dirp))) {
764  sprintf(file, "%s/%s", dir, ep->d_name);
765  f_gisman = fopen(file, "r");
766  if ((!strcmp(ep->d_name, ".")) || (!strcmp(ep->d_name, ".."))) {
767  fclose(f_gisman);
768  continue;
769  }
770  if (f_gisman == NULL) {
771  fclose(f_gisman);
772  continue;
773  }
774  /* count number of lines in file */
775  while (fgets(str, MAXSTR, f_gisman) != NULL) {
776  n_entries++;
777  }
778  n_files++;
779  fclose(f_gisman);
780  }
781  closedir(dirp);
782 
783  /* count number of lines in menu.tcl */
784  n_lines = 0;
785  while (fgets(str, MAXSTR, f_in) != NULL) {
786  n_lines++;
787  }
788  if (n_lines == 0) {
789  return (0);
790  }
791  rewind(f_in);
792 
793  /* create an array large enough to hold all lines in menu.tcl */
794  /* plus the entries that are to be added from the files in gem-entries/ */
795  /* plus space for uninstall comments */
796  /* plus one NULL terminator */
797  /* and copy all lines from menu.tcl into this */
798  line =
799  (char **)calloc(n_lines + (n_entries * 2) + (n_files * 5) + 1,
800  sizeof(char *));
801  for (i = 0; i < (n_lines + (n_entries * 2) + (n_files * 5) + 1); i++) {
802  line[i] = NULL;
803  }
804  i = 0;
805  while (fgets(str, MAXSTR, f_in) != NULL) {
806  line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
807  strcpy(line[i], str);
808  i++;
809  }
810  line[i] = NULL; /* add NULL terminator */
811 
812  check_ext_menu(line); /* create "Extensions" menu if necessary */
813 
814  /* PASS 2: re-create submenus and all menu items if necessary */
815  dirp = opendir(dir);
816  num_restored = 0;
817  while ((ep = readdir(dirp))) {
818  sprintf(file, "%s/%s", dir, ep->d_name);
819  if ((!strcmp(ep->d_name, ".")) || (!strcmp(ep->d_name, ".."))) {
820  continue;
821  }
822  f_gisman = fopen(file, "r");
823  if (f_gisman == NULL) {
824  continue;
825  }
826  /* read all lines from entries-gisman and add to menus */
827  i = 1;
828  while (nc_fgets_nb(str, MAXSTR, f_gisman) != NULL) {
829  if (i == 1) {
830  /* store name of menu item */
831  len = (strrchr(str, ']') - strchr(str, '[')) / sizeof(char);
832  strncpy(menu, strchr(str, '[') + sizeof(char), len);
833  menu[len - 1] = '\0'; /* get rid of [] */
834  line_no = new_submenu(pkg_short_name, str, line);
835  if (line_no < 0) {
836  break;
837  }
838  i++;
839  num_restored++;
840  }
841  else {
842  line_no = new_item(str, menu, line, line_no);
843  if (line_no < 0) {
844  break;
845  }
846  i++;
847  num_restored++;
848  }
849  }
850  fclose(f_gisman);
851  }
852  closedir(dirp);
853 
854  /* write output to tmpfile */
855  i = 0;
856  while (line[i] != NULL) {
857  fprintf(f_out, line[i]);
858  i++;
859  }
860  fflush(f_out);
861 
862  /* close remaining files */
863  fclose(f_in);
864  fclose(f_out);
865 
866  /* free memory */
867  for (i = 0; i < (n_lines + (n_entries * 2) + (n_files * 5) + 1); i++) {
868  free(line[i]);
869  }
870  free(line);
871 
872  return (num_restored);
873 }
EXTERN int VERBOSE
Definition: globals.h:147
void exit_db(void)
int restore_entries_gisman(char *gisbase)
Definition: reg_entries.c:692
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
DIR * opendir()
#define MAXSTR
Definition: globals.h:59
int new_item(char *item, char *menu, char **tcl_lines, int line_no)
Definition: reg_entries.c:173
EXTERN char GISMAN2_CMD[MAXSTR]
Definition: globals.h:166
EXTERN char TMP_NULL[MAXSTR]
Definition: globals.h:156
void print_error(int err_code, char *msg,...)
Definition: gem/error.c:32
int check_ext_menu(char **tcl_lines)
Definition: reg_entries.c:57
tuple pos
Definition: tools.py:1367
int delete_str(int pos, char **strarr)
Definition: tools.c:190
list command
Definition: render.py:1315
tuple gisbase
Definition: forms.py:59
dir_entry * readdir()
int deregister_entries_gisman(char *pkg_short_name, char *gisbase)
Definition: reg_entries.c:461
void register_entries_gisman(char *pkg_short_name, char *gisbase)
Definition: reg_entries.c:232
#define ERR_REGISTER_ENTRIES_GISMAN2
Definition: globals.h:108
void * malloc(YYSIZE_T)
string menu
int new_submenu(char *pkg_short_name, char *menu, char **tcl_lines)
Definition: reg_entries.c:90
int is_submenu(char *item)
Definition: reg_entries.c:36
#define ERR_REGISTER_ENTRIES_GISMAN
Definition: globals.h:97
void deregister_entries_gisman2(char *pkg_short_name, char *gisbase)
Definition: reg_entries.c:653
#define ERR_DEREGISTER_ENTRIES_GISMAN2
Definition: globals.h:109
#define ERR_DEREGISTER_ENTRIES_GISMAN
Definition: globals.h:98
int find_pos(char *str, char **strarr, int start)
Definition: tools.c:230
void print_warning(char *msg,...)
Definition: gem/error.c:52
return NULL
Definition: dbfopen.c:1394
int chop(char *string)
Definition: tools.c:86
int insert_str(char *str, int pos, char **strarr)
Definition: tools.c:125
fclose(fd)
void free(void *)
#define file
void register_entries_gisman2(char *pkg_short_name, char *gisbase)
Definition: reg_entries.c:415
int errno
char * nc_fgets_nb(char *s, int size, FILE *stream)
Definition: tools.c:500
int menu_created
Definition: reg_entries.c:29
EXTERN char GISMAN_CMD[MAXSTR]
Definition: globals.h:165
EXTERN char TMP_GISMAN[MAXSTR]
Definition: globals.h:150