123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 |
- /***************************************************************************
- * tools.c
- *
- * Mon Apr 18 15:00:13 2005
- * Copyright 2005 Benjamin Ducke
- ****************************************************************************/
- /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "globals.h"
- /* the following are for cross-platform compatibility. They may already exist
- on a Linux or BSD system, but maybe absent e.g. in Win32, so we will define
- them here. */
- char *basename(char *path)
- {
- char *copy;
- char *element;
- char *backup;
- copy = strdup(path);
- backup = NULL;
- element = strtok(copy, "/");
- if (element == NULL) {
- if (copy != NULL) {
- free(copy);
- }
- return (NULL);
- }
- backup = strdup(element);
- while (element != NULL) {
- element = strtok(NULL, "/");
- if ((backup != NULL) && (element != NULL)) {
- free(backup);
- }
- if ((element != NULL) && (element != "")) {
- backup = strdup(element);
- }
- }
- if (copy != NULL) {
- free(copy);
- }
- return (backup);
- }
- /* A shell version of mkdir ()
- needed because the MINGW one does no accept unix style MOD specifications.
- THIS DOES NOT CHECK FOR ERRORS !
- */
- void mkdir_s(char *pathname, char *mode)
- {
- char tmp[5000];
- sprintf(tmp, "mkdir %s --mode=%s -p", pathname, mode);
- system(tmp);
- }
- /*
- Removes all dangling white-spaces and EOL chars from the end of a string.
- Returns total number of chopped-off characters.
- */
- int chop(char *string)
- {
- int i;
- int chopped;
- int stop = 0;
- chopped = 0;
- i = strlen(string) - 1;
- while (i >= 0) {
- stop = 1;
- if ((string[i] == '\n') || (string[i] == '\t') ||
- (string[i] == ' ') || (string[i] == '\f') ||
- (string[i] == '\r')) {
- chopped++;
- stop = 0;
- }
- if (stop == 1) {
- /* got a non white-space char: stop chopping! */
- break;
- }
- i--;
- }
- /* chop string */
- string[strlen(string) - chopped] = '\0';
- return (chopped);
- }
- /*
- Inserts a string into an array of n strings; positions start at 0
- The size of the array will be increased by one char*.
- Returns new size of array.
- String array must be NULL-terminated.
- There must be at least one slots left after the NULL-terminator to
- hold the new string! This function will not resize the string
- array to accomodate the new string!
- */
- int insert_str(char *str, int pos, char **strarr)
- {
- char save[MAXSTR];
- char insert[MAXSTR];
- char last[MAXSTR];
- int n, j;
- int len;
- /* check for valid pos */
- n = 0;
- while (strarr[n] != NULL) {
- n++;
- }
- if ((pos < 0) || (pos > (n))) {
- print_error(ERR_REGISTER_ENTRIES_GISMAN,
- "insert: invalid line number %i.\n", pos);
- }
- /* if a new string is to be added to the end of the array: */
- if (pos == n) {
- len = (1 + strlen(str)) * sizeof(char);
- strarr[n] = malloc(len);
- strcpy(strarr[n], str);
- n = n + 2;
- strarr[n - 1] = NULL;
- return (n);
- }
- strcpy(last, strarr[n - 1]);
- strcpy(insert, strarr[pos]);
- free(strarr[pos]);
- strarr[pos] = malloc((1 + strlen(str)) * sizeof(char));
- strcpy(strarr[pos], str);
- /* now move all strings > pos up one */
- for (j = pos; j < n - 1; j++) {
- strcpy(save, strarr[j + 1]); /* save string to be overwritten */
- free(strarr[j + 1]); /* overwrite string */
- len = (1 + strlen(insert)) * sizeof(char); /* make room for string to be inserted */
- strarr[j + 1] = malloc(len);
- strcpy(strarr[j + 1], insert); /* insert string */
- strcpy(insert, save); /* set saved string to next to be inserted */
- }
- /* overwrite NULL terminator with last item */
- strarr[n] = malloc((1 + strlen(last)) * sizeof(char));
- strcpy(strarr[n], last);
- /* increase size of array by one */
- n = n + 2;
- strarr[n - 1] = NULL; /* set last element of array to NULL */
- return (n);
- }
- /*
- Delete a string at position pos (o to n) from an array of n strings;
- positions start at 0
- The size of the array will be decreased by one char*.
- Returns new size of array.
- String array must be NULL-terminated.
- */
- int delete_str(int pos, char **strarr)
- {
- int i;
- /* check for valid pos */
- i = 0;
- while (strarr[i] != NULL) {
- i++;
- }
- if ((pos < 0) || (pos > (i))) {
- print_error(ERR_REGISTER_ENTRIES_GISMAN,
- "delete: invalid line number %i.\n", pos);
- }
- /* now move all strings > pos down one */
- i = pos;
- while (strarr[i] != NULL) {
- free(strarr[i]);
- if (strarr[i + 1] != NULL) {
- strarr[i] = malloc((1 + (strlen(strarr[i + 1]))) * sizeof(char));
- strcpy(strarr[i], strarr[i + 1]);
- }
- i++;
- }
- /* decrease size of array by one */
- i = i - 1;
- strarr[i] = NULL; /* set last element of array to NULL */
- return (i);
- }
- /*
- Returns the first line number in which *str is found.
- Search starts after line number 'start'.
- Returns -1 if string not found.
- String array must be NULL-terminated.
- */
- int find_pos(char *str, char **strarr, int start)
- {
- int i, j;
- /* check for valid pos */
- i = 0;
- while (strarr[i] != NULL) {
- i++;
- }
- if ((start < 0) || (start > (i))) {
- exit(ERR_REGISTER_ENTRIES_GISMAN);
- }
- for (j = start; j < (i); j++) {
- if (strstr(strarr[j], str) != NULL) {
- return (j);
- }
- }
- return (-1);
- }
- /*
- Dumps an array of strings to a file.
- String array must be NULL-terminated.
- */
- void dump_str(FILE * f, char **strarr)
- {
- int i;
- i = 0;
- while (strarr[i] != NULL) {
- fprintf(f, "%i: %s", i, strarr[i]);
- i++;
- }
- }
- /*
- Get package name. Copies the package name as found in
- the 'name' info file into the char array *name.
- */
- void get_package_name(char *path, char *name)
- {
- FILE *f;
- char file[MAXSTR];
- char tmp[MAXSTR];
- sprintf(file, "%s/%s", path, "name");
- /* get extension name */
- f = fopen(file, "r");
- if (f == NULL) {
- print_error(ERR_INVALID_EXT, "'name' file not readable.\n");
- }
- else {
- if (nc_fgets_nb(tmp, MAXSTR, f) == NULL) {
- fclose(f);
- print_error(ERR_INVALID_EXT,
- "invalid or missing extension name.\n");
- }
- else {
- chop(tmp);
- strcpy(name, tmp);
- }
- }
- fclose(f);
- }
- /*
- A replacement function for fgets to filter out comments and blank lines.
- Useful for parsing settings files.
- Returns a line from a file only if it does not start with '#'.
- Returns only the part of the line left of '#'.
- Otherwise, tries to read the next line from the file or returns NULL on EOF.
- */
- char *nc_fgets(char *s, int size, FILE * stream)
- {
- char *hashmark;
- char *tmp;
- if (fgets(s, size, stream) == NULL) {
- return (NULL);
- }
- hashmark = strchr(s, '#');
- if (hashmark != NULL) {
- if (s - hashmark == 0) {
- /* line starts with a hashmark: recursively call nc_fgets() */
- return (nc_fgets(s, size, stream));
- }
- else {
- /* return only the part before '#' */
- tmp = malloc(sizeof(char) * MAXSTR);
- strcpy(tmp, s);
- tmp = strtok(tmp, "#");
- sprintf(s, "%s\n", tmp);
- free(tmp);
- }
- }
- return (s);
- }
- /*
- Same as nc_fgets (). Additionally, this filters for HTML tags.
- */
- char *nc_fgets_html(char *s, int size, FILE * stream)
- {
- char *hashmark;
- char *tmp;
- char *tag;
- char *tag_2;
- char *tag_insert;
- char *tag_content;
- char *pos;
- char *insert;
- int space;
- if (fgets(s, size, stream) == NULL) {
- return (NULL);
- }
- /* look for HTML tags: this discards all text inside the tags except for:
- <br> becomes \n
- <p> becomes \n\n
- */
- tmp = malloc(sizeof(char) * (strlen(s) + 1));
- tag_content = malloc(sizeof(char) * (strlen(s) + 1));
- insert = tmp;
- pos = s;
- while (*pos != '\0') {
- if (*pos == '<') { /* possibly an html open tag */
- tag = pos;
- tag_insert = tag_content;
- pos--;
- if (pos >= s) {
- if (*pos == 32) {
- space = 1;
- }
- else {
- space = 0;
- }
- }
- while (*tag != '\0') {
- *tag_insert = *tag;
- (*tag_insert)++;
- if (*tag == '>') { /* OK, we got a tag */
- *tag_insert = '\0';
- /* only add additional newlines, if this is not the end of the line already! */
- tag_2 = tag;
- tag_2++;
- if (*tag_2 != '\n') {
- if (strstr(tag_content, "<br>") != NULL) {
- /* a <br> at the start of a line produce no additional linefeed! */
- if (insert > tmp) {
- *insert = '\n';
- (*insert)++;
- }
- }
- if (strstr(tag_content, "<BR>") != NULL) {
- if (insert > tmp) {
- *insert = '\n';
- (*insert)++;
- }
- }
- if (strstr(tag_content, "<p>") != NULL) {
- if (insert > tmp) {
- *insert = '\n';
- (*insert)++;
- }
- *insert = '\n';
- (*insert)++;
- }
- if (strstr(tag_content, "<P>") != NULL) {
- if (insert > tmp) {
- *insert = '\n';
- (*insert)++;
- }
- *insert = '\n';
- (*insert)++;
- }
- }
- pos = tag; /* skip this */
- /* if the next character is a space and there was none
- before the tag: skip that, too
- */
- if (*pos == 32) {
- if (space == 1) {
- pos++;
- space = 0;
- }
- }
- break;
- }
- tag++;
- }
- }
- if (*pos != '>') {
- *insert = *pos;
- insert++;
- }
- pos++;
- }
- *insert = '\0';
- strcpy(s, tmp);
- free(tmp);
- free(tag_content);
- hashmark = strchr(s, '#');
- if (hashmark != NULL) {
- if (s - hashmark == 0) {
- /* line starts with a hashmark: recursively call nc_fgets_html() */
- return (nc_fgets_html(s, size, stream));
- }
- else {
- /* return only the part before '#' */
- tmp = malloc(sizeof(char) * MAXSTR);
- strcpy(tmp, s);
- tmp = strtok(tmp, "#");
- sprintf(s, "%s\n", tmp);
- free(tmp);
- }
- }
- return (s);
- }
- /*
- Checks whether a string actually contains text or is a blank line/whitespace only.
- Returns 1 if text , 0 if only blank/whitespace.
- */
- int is_text(char *s)
- {
- int i;
- int nonws;
- /* check for a blank or white-space only line */
- nonws = 0;
- for (i = strlen(s) - 1; i >= 0; i--) {
- if ((s[i] == ' ') || (s[i] == '\t') || (s[i] == '\n') ||
- (s[i] == '\f') || (s[i] == '\r')) {
- nonws = 0;
- }
- else {
- nonws = 1;
- break; /* break at first non-ws char! */
- }
- }
- return (nonws);
- }
- /*
- Same as nc_fgets() but also skips over blank lines and those that contain only
- whitespace chars.
- */
- char *nc_fgets_nb(char *s, int size, FILE * stream)
- {
- char *hashmark;
- char *tmp;
- if (fgets(s, size, stream) == NULL) {
- return (NULL);
- }
- if (is_text(s) == 0) {
- /* line is ws only: recursively call nc_fgets() to get next line */
- return (nc_fgets_nb(s, size, stream));
- }
- hashmark = strchr(s, '#');
- if (hashmark != NULL) {
- if (s - hashmark == 0) {
- /* line starts with a hashmark: recursively call nc_fgets() */
- return (nc_fgets_nb(s, size, stream));
- }
- else {
- /* return only the part before '#' */
- tmp = malloc(sizeof(char) * MAXSTR);
- strcpy(tmp, s);
- tmp = strtok(tmp, "#");
- sprintf(s, "%s\n", tmp);
- free(tmp);
- }
- }
- return (s);
- }
- /*
- This just dumps an ASCII file to stdout, line by line, but
- skips over comments.
- */
- void dump_ascii(char *file, char *heading)
- {
- char tmp[MAXSTR];
- FILE *f;
- fprintf(stdout, "%s\n", heading);
- f = fopen(file, "r");
- if (f == NULL) {
- fprintf(stdout, " No information available.\n");
- }
- else {
- while (nc_fgets_html(tmp, MAXSTR, f) != NULL) {
- fprintf(stdout, " %s", tmp);
- }
- fprintf(stdout, "\n");
- fclose(f);
- }
- }
- /*
- Dumps the contents of an ASCII file without comment lines but with blank lines
- to a temporary file.
- */
- void dump_plain(char *file, char *tmpfile)
- {
- char tmp[MAXSTR];
- FILE *f_in;
- FILE *f_out;
- /* create a temporary menu.tcl file for write access */
- /* TODO: Do not hardcode temp path */
- strcpy(tmpfile, "/tmp/grass.extensions.db.XXXXXX"); /* TMP_GISMAN is a global variable */
- mkstemp(tmpfile);
- f_out = fopen(tmpfile, "w+");
- if (f_out == NULL) {
- print_error(ERR_DUMP_PLAIN_TXT,
- "could not create temp file '%s': %s\n \
- Make sure that directory /tmp exists on your system and you have write permission.\n", tmpfile, strerror(errno));
- }
- atexit(&exit_db); /* now need to register an at exit func to remove tmpfile automatically! */
- f_in = fopen(file, "r");
- while (nc_fgets(tmp, MAXSTR, f_in) != NULL) {
- fprintf(f_out, tmp);
- }
- fclose(f_in);
- fclose(f_out);
- }
- /*
- Same as dump_plain() but adds a <br> after each newline in the stream.
- Also replaces blank lines with a <p>.
- */
- void dump_html(char *file, char *tmpfile)
- {
- char tmp[MAXSTR];
- char line[MAXSTR];
- FILE *f_in;
- FILE *f_out;
- int fd;
- /* create a temporary menu.tcl file for write access */
- /* TODO: Do not hardcode temp path */
- strcpy(tmpfile, "/tmp/grass.extensions.db.XXXXXX"); /* TMP_GISMAN is a global variable */
- mkstemp(tmpfile);
- f_out = fopen(tmpfile, "w+");
- if (f_out == NULL) {
- print_error(ERR_DUMP_PLAIN_TXT,
- "could not create temp file '%s': %s\n \
- Make sure that directory /tmp exists on your system and you have write permission.\n", tmpfile, strerror(errno));
- }
- atexit(&exit_db); /* now need to register an at exit func to remove tmpfile automatically! */
- f_in = fopen(file, "r");
- while (nc_fgets(line, MAXSTR, f_in) != NULL) {
- chop(line);
- if (!is_text(line)) { /* replace blank lines with a <p> */
- fprintf(f_out, "<p>\n");
- }
- else {
- sprintf(tmp, "%s <br>\n", line);
- fprintf(f_out, tmp);
- }
- }
- fclose(f_in);
- fclose(f_out);
- close(fd);
- }
- /*
- A pretty dumb function: this just lists all directories which are directly below
- top level and not called "src". It is assumed that these contain binary distributions
- which can be installed by just doing a "make install" in the respective directory.
- */
- void list_binaries(char *package)
- {
- char tmp[MAXSTR];
- struct stat buf;
- DIR *dir;
- struct dirent *dir_entry;
- int n_dirs = 0;
- fprintf(stdout, "Binary installation files\n");
- dir = opendir(package);
- if (dir == NULL) {
- fprintf(stdout, " None.\n\n");
- return;
- }
- dir_entry = readdir(dir);
- while (dir_entry != NULL) {
- if ((strcmp(dir_entry->d_name, ".")) &&
- (strcmp(dir_entry->d_name, "..")) &&
- (strcmp(dir_entry->d_name, "src"))
- ) {
- /* check if it is a directory */
- sprintf(tmp, "%s/%s", package, dir_entry->d_name);
- stat(tmp, &buf);
- if (S_ISDIR(buf.st_mode)) {
- if (n_dirs == 0) {
- fprintf(stdout, " %s", dir_entry->d_name);
- }
- else {
- fprintf(stdout, ", %s", dir_entry->d_name);
- }
- n_dirs++;
- }
- }
- dir_entry = readdir(dir);
- }
- if (n_dirs == 0) {
- fprintf(stdout, " None.");
- }
- fprintf(stdout, "\n\n");
- }
- /*
- Just as dumb: checks, if a specified directory 'binaries' exists in addition to 'src'
- Returns 1 if so, 0 otherwise
- */
- int binaries_exist(char *package, char *binaries)
- {
- char tmp[MAXSTR];
- struct stat buf;
- DIR *dir;
- struct dirent *dir_entry;
- dir = opendir(package);
- if (dir == NULL) {
- return (0);
- }
- dir_entry = readdir(dir);
- while (dir_entry != NULL) {
- if ((strcmp(dir_entry->d_name, ".")) &&
- (strcmp(dir_entry->d_name, "..")) &&
- (strcmp(dir_entry->d_name, "src"))
- ) {
- /* check if it is a directory */
- sprintf(tmp, "%s/%s", package, dir_entry->d_name);
- stat(tmp, &buf);
- if (S_ISDIR(buf.st_mode)) {
- if (!strcmp(dir_entry->d_name, binaries)) {
- return (1); /* found it */
- }
- }
- }
- dir_entry = readdir(dir);
- }
- return (0);
- }
- /*
- Tests for a known file-extension:
- .tar.gz, .tgz
- .tar.bz2, .tbz
- .zip
- Returns:
- 0 = unknown (TYPE_UNKNOWN)
- 1 = tar file with gzip compression (TAR_GZIP)
- 2 = tar file with bzip2 compression (TAR_BZIP2)
- 3 = zip archive (ZIP)
- 4 = plain tar archive, uncompressed (TAR)
- VERY primitive!
- */
- int check_filetype(char *myfile)
- {
- if (strstr(myfile, ".tar.gz") != NULL) {
- return (1);
- }
- if (strstr(myfile, ".tgz") != NULL) {
- return (1);
- }
- if (strstr(myfile, ".tar.bz2") != NULL) {
- return (2);
- }
- if (strstr(myfile, ".tbz") != NULL) {
- return (2);
- }
- if (strstr(myfile, ".zip") != NULL) {
- return (3);
- }
- if (strstr(myfile, ".tar") != NULL) {
- return (4);
- }
- return (0);
- }
- /*
- Retrieves an extension from the WWW using wget and
- stores the file in the current directory.
- */
- void wget_extension(char *url)
- {
- char str[MAXSTR];
- int error;
- fprintf(stdout, "Downloading...");
- if (VERBOSE) {
- sprintf(str, "wget -N %s", url);
- }
- else {
- sprintf(str, "wget -N -q %s", url);
- }
- error = system(str);
- if (error == -1) {
- print_error(ERR_DOWNLOAD,
- "could not run 'wget' to download extension. Is it installed?\n");
- }
- if (error > 0) {
- print_error(ERR_DOWNLOAD, "running command '%s'.\n", str);
- }
- print_done();
- }
- /*
- This function checks if there is write access to the GRASS directory.
- If not, it aborts with an error message.
- Otherwise, 'cmd' is simply executed as currently running user.
- */
- void su(char *gisbase, char *cmd)
- {
- char tmpfile[MAXSTR];
- int error;
- static unsigned long next;
- FILE *f;
- /* check for permission */
- next = next * 1103515245 + 54321; /* generate a random file name */
- next = (next / 65536) % 32768;
- srand(next);
- sprintf(tmpfile, "%s/gem.test.%i", gisbase, rand());
- f = fopen(tmpfile, "w+");
- if (errno == EACCES) { /* permission denied */
- print_error(ERR_INSTALL_EXT,
- "You don't have write access to your local GRASS installation.\nPlease consult your system administrator.\n");
- }
- else {
- remove(tmpfile);
- fclose(f);
- error = system(cmd);
- if (error != 0) {
- print_error(ERR_MISSING_CMD, "could not run '%s'.\n", cmd);
- }
- }
- }
- /*
- Compares two version descriptions consisting of three ints each
- returns: -1, if major.minor.revision < major2.minor2.revision2,
- 0, if equal
- 1, if major.minor.revision > major2.minor2.revision2,
- */
- int vercmp(int major, int minor, int revision, int major2, int minor2,
- int revision2)
- {
- if ((major == major2) && (minor == minor2) && (revision == revision2)) {
- return (0);
- }
- if (major2 > major) {
- return (-1);
- }
- if (major2 < major) {
- return (1);
- }
- if (minor2 > minor) {
- return (-1);
- }
- if (minor2 < minor) {
- return (1);
- }
- if (revision2 > revision) {
- return (-1);
- }
- if (revision2 < revision) {
- return (1);
- }
- return (0);
- }
|