2
/***************************************************************************
5
* Fri May 13 11:35:33 2005
8
****************************************************************************/
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.
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.
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.
33
Returns 1, if the string is a submenu item, 0 otherwise.
36
int is_submenu(char *item)
38
if (strchr(item, '[') == NULL) {
41
if (strrchr(item, ']') == NULL) {
44
if (strchr(item, '[') > strrchr(item, ']')) {
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
57
int check_ext_menu(char **tcl_lines)
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);
68
print_error(ERR_REGISTER_ENTRIES_GISMAN,
69
"could not parse 'menu.tcl'.\n");
71
insert_str(" \"&Xtns\" all options 1 {\n", idx, tcl_lines);
73
insert_str(" }\n", idx, tcl_lines);
76
insert_str(" \"&Xtns\" all options 1 {\n", idx, tcl_lines);
78
insert_str(" }\n", idx, tcl_lines);
85
Creates a new submenu for this extension under "Extensions" in GIS Managers
87
Returns line no. of submenu, after which additional entries should be appended
90
int new_submenu(char *pkg_short_name, char *menu, char **tcl_lines)
94
char searchstr[MAXSTR];
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 */
107
last = find_pos("}]", tcl_lines, 0); /* end of menu.tcl */
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");
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 */
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",
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) {
145
idx2 = find_pos("{cascad ", tcl_lines, idx);
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);
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);
160
/* return next line for insertion of menu entries and commands! */
161
return (insert_here + 1);
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
173
int new_item(char *item, char *menu, char **tcl_lines, int line_no)
178
char command[MAXSTR];
182
/* remove dangling white spaces and EOL chars */
185
token = strtok(item, ";");
187
print_warning("invalid token in 'entries-gisman'.\n");
191
strcpy(entry, token); /* get menu entry string */
194
while (token != NULL) {
195
token = strtok(NULL, ";");
197
strcpy(command, token); /* get command string */
202
if (num_tokens > 2) {
203
print_warning("invalid number of tokens (%i) in 'entries-gisman'.\n",
208
/* just a separator or a 'real' menu entry? */
209
if ((!strcmp(entry, "-")) && (!strcmp(entry, "-"))) {
210
sprintf(tmp, " \t\t\t {separator}\n");
213
sprintf(tmp, " \t\t\t {command \"%s\" {} \"%s\" {} -command {%s }}\n",
214
entry, command, command);
216
insert_str(tmp, line_no, tcl_lines);
218
/* return line no. for next entry */
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.
232
void register_entries_gisman(char *pkg_short_name, char *gisbase)
240
int n_entries, n_lines, i;
241
int n_lines_org, n_lines_new;
243
FILE *f_gisman, *f_in, *f_out;
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 */
254
/* sth. strange happened */
256
print_error(ERR_REGISTER_ENTRIES_GISMAN,
257
"checking for file '%s': %s\n", file,
262
/* check if menu.tcl exists and is readable */
263
sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
264
f_in = fopen(file, "r");
266
if (errno == ENOENT) {
267
/* file does not exist */
271
/* sth. strange happened */
273
print_error(ERR_REGISTER_ENTRIES_GISMAN,
274
"checking for file '%s': %s\n", file,
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 */
284
f_out = fopen(TMP_GISMAN, "w+");
286
print_error(ERR_REGISTER_ENTRIES_GISMAN,
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));
290
atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
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 */
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);
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);
308
strcpy(GISMAN_CMD, str);
310
/* count number of lines in entries-gisman */
312
while (fgets(str, MAXSTR, f_gisman) != NULL) {
315
if (n_entries == 0) {
320
/* count number of lines in menu.tcl */
322
while (fgets(str, MAXSTR, f_in) != NULL) {
328
n_lines_org = n_lines;
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++) {
340
while (fgets(str, MAXSTR, f_in) != NULL) {
341
line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
342
strcpy(line[i], str);
346
check_ext_menu(line); /* create "Extensions" menu if necessary */
348
/* read all lines from entries-gisman and add to menus */
350
while (nc_fgets_nb(str, MAXSTR, f_gisman) != NULL) {
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);
358
print_warning("no GIS Manager menu entries created.\n");
364
line_no = new_item(str, menu, line, line_no);
366
print_warning("error creating GIS Manager menu entries.\n");
373
/* write output to tmpfile */
375
while (line[i] != NULL) {
376
fprintf(f_out, line[i]);
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! */
385
while (fgets(str, MAXSTR, f_out) != NULL) {
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, "");
400
for (i = 0; i < (n_lines + (n_entries * 2) + 6); i++) {
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!
415
void register_entries_gisman2(char *pkg_short_name, char *gisbase)
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 */
430
/* sth. strange happened */
432
print_error(ERR_REGISTER_ENTRIES_GISMAN2,
433
"checking for file '%s': %s\n", file,
438
/* let's just blindly create an 'Xtns' dir: if it exists already: no problem */
439
/* and then copy file into it! */
442
"mkdir --verbose -p %s/etc/gm/Xtns ; cp -fv ../entries-gisman2 %s/etc/gm/Xtns/%s.gem ; ",
443
gisbase, gisbase, pkg_short_name);
447
"mkdir -p %s/etc/gm/Xtns ; cp -f ../entries-gisman2 %s/etc/gm/Xtns/%s.gem ; ",
448
gisbase, gisbase, pkg_short_name);
450
strcpy(GISMAN2_CMD, str);
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.
461
int deregister_entries_gisman(char *pkg_short_name, char *gisbase)
468
int n_lines_org, n_lines_new;
472
int start_sub, end_sub;
476
/* check if menu.tcl exists and is readable */
477
sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
478
f_in = fopen(file, "r");
480
if (errno == ENOENT) {
481
/* file does not exist */
485
/* sth. strange happened */
487
print_error(ERR_DEREGISTER_ENTRIES_GISMAN,
488
"checking for file '%s': %s\n", file,
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 */
498
f_out = fopen(TMP_GISMAN, "w+");
500
print_error(ERR_REGISTER_ENTRIES_GISMAN,
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));
504
atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
506
/* everything fine: create a shell command to copy modified menu.tcl on uninstall */
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);
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);
516
strcpy(GISMAN_CMD, str);
519
/* count number of lines in menu.tcl */
521
while (fgets(str, MAXSTR, f_in) != NULL) {
528
n_lines_org = n_lines;
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++) {
538
while (fgets(str, MAXSTR, f_in) != NULL) {
539
line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
540
strcpy(line[i], str);
544
/* search for uninstall comment */
545
sprintf(str, "#(DO_NOT_REMOVE_THIS_COMMENT) <%s> {cascad",
547
pos = find_pos(str, line, 0);
550
("could not find uninstall information in 'menu.tcl'.\n");
554
/* copy name of submenu to search for */
555
lq = strchr(line[pos], '\"');
557
rq = strchr(lq, '\"');
559
tmp[(rq - lq) / sizeof(char)] = '\0';
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;
565
end = find_pos("}]", line, 0); /* end of menu.tcl */
569
print_warning("menu 'Xtns' does not exist.\n");
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",
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",
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);
597
/* now kill the uninstall comment */
598
sprintf(str, "#(DO_NOT_REMOVE_THIS_COMMENT) <%s> {cascad",
600
pos = find_pos(str, line, 0);
601
delete_str(pos, line);
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);
614
/* write output to tmpfile */
616
while (line[i] != NULL) {
617
fprintf(f_out, line[i]);
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! */
626
while (fgets(str, MAXSTR, f_out) != NULL) {
629
if ((n_lines_new == 0)) {
631
("file truncation detected. Retaining orginal file 'menu.tcl'.\n");
632
strcpy(GISMAN_CMD, "");
640
for (i = 0; i < n_lines + 1; i++) {
645
return (num_removed);
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!
653
void deregister_entries_gisman2(char *pkg_short_name, char *gisbase)
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 */
668
/* sth. strange happened */
670
print_error(ERR_DEREGISTER_ENTRIES_GISMAN2,
671
"checking for file '%s': %s\n", file,
677
sprintf(str, "rm -vf %s/etc/gm/Xtns/%s.gem ; ",
678
gisbase, pkg_short_name);
681
sprintf(str, "rm -f %s/etc/gm/Xtns/%s.gem ; ",
682
gisbase, pkg_short_name);
685
strcpy(GISMAN_CMD, str);
690
Returns number of restored entries
692
int restore_entries_gisman(char *gisbase)
698
char pkg_short_name[MAXSTR];
701
int n_entries, n_lines, i;
703
FILE *f_gisman, *f_in, *f_out;
709
/* check if menu.tcl exists and is readable */
710
sprintf(file, "%s/etc/dm/menu.tcl", gisbase);
711
f_in = fopen(file, "r");
713
if (errno == ENOENT) {
714
/* file does not exist */
718
/* sth. strange happened */
720
print_error(ERR_REGISTER_ENTRIES_GISMAN,
721
"checking for file '%s': %s\n", file,
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 */
731
f_out = fopen(TMP_GISMAN, "w+");
733
print_error(ERR_REGISTER_ENTRIES_GISMAN,
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));
737
atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
739
/* everything fine: create a shell command to copy modified menu.tcl on uninstall */
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);
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);
749
strcpy(GISMAN_CMD, str);
751
/* allocate a pointer to the directory structure */
752
sprintf(dir, "%s/etc/dm/gem-entries", gisbase);
755
/* directory does not exist or is not accessible */
760
/* open all files in gem-entries and count the number of lines each has */
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, ".."))) {
770
if (f_gisman == NULL) {
774
/* count number of lines in file */
775
while (fgets(str, MAXSTR, f_gisman) != NULL) {
783
/* count number of lines in menu.tcl */
785
while (fgets(str, MAXSTR, f_in) != NULL) {
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 */
799
(char **)calloc(n_lines + (n_entries * 2) + (n_files * 5) + 1,
801
for (i = 0; i < (n_lines + (n_entries * 2) + (n_files * 5) + 1); i++) {
805
while (fgets(str, MAXSTR, f_in) != NULL) {
806
line[i] = (char *)malloc((1 + strlen(str)) * sizeof(char));
807
strcpy(line[i], str);
810
line[i] = NULL; /* add NULL terminator */
812
check_ext_menu(line); /* create "Extensions" menu if necessary */
814
/* PASS 2: re-create submenus and all menu items if necessary */
817
while ((ep = readdir(dirp))) {
818
sprintf(file, "%s/%s", dir, ep->d_name);
819
if ((!strcmp(ep->d_name, ".")) || (!strcmp(ep->d_name, ".."))) {
822
f_gisman = fopen(file, "r");
823
if (f_gisman == NULL) {
826
/* read all lines from entries-gisman and add to menus */
828
while (nc_fgets_nb(str, MAXSTR, f_gisman) != NULL) {
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);
842
line_no = new_item(str, menu, line, line_no);
854
/* write output to tmpfile */
856
while (line[i] != NULL) {
857
fprintf(f_out, line[i]);
862
/* close remaining files */
867
for (i = 0; i < (n_lines + (n_entries * 2) + (n_files * 5) + 1); i++) {
872
return (num_restored);