diff options
Diffstat (limited to 'src/hyper/htadd.c')
-rw-r--r-- | src/hyper/htadd.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/src/hyper/htadd.c b/src/hyper/htadd.c new file mode 100644 index 00000000..02ec8f84 --- /dev/null +++ b/src/hyper/htadd.c @@ -0,0 +1,537 @@ +/* + Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd. + All rights reserved. + Copyright (C) 2007-2008, Gabriel Dos Reis. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of The Numerical Algorithms Group Ltd. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* HyperDoc database file manager */ + + +#define _HTADD_C +#include "axiom-c-macros.h" +#include "useproto.h" +#include "hyper.h" +#include <sys/stat.h> +#include <errno.h> +#include <setjmp.h> + +#include "lex.h" + +#include "htadd.H1" +#include "addfile.H1" +#include "halloc.H1" +#include "hash.H1" +#include "hterror.H1" +#include "lex.H1" + + + + +/* + * These are variables that htadd needs to have declared because it shares + * the lexical analyzer with HyperDoc + */ + +int gTtFontIs850=0; +HDWindow *gWindow = NULL; +extern int line_number; /* keeps track of which line a page starts on + * in a file. This way someone can start + * including a line number counter into + * HyperDoc. */ +/* for compatibility with HyperDoc */ +Sock *spad_socket = NULL; +Sock *session_server = NULL; +int MenuServerOpened; +Display *gXDisplay; +int gXScreenNumber; +int fresh = 0; + +#define Delete 1 +#define System 2 +#define Current 4 +#define Named 8 + +#define usage "usage: htadd [-s|-l|-f db-directory] [-d|-n] filenames" + + +int +main(int argc, char **argv) +{ + /*int i;*/ + char db_dir[256]; /* the directory where the db file is */ + char dbfilename[256]; /* the database filename */ + char *filenames[1000]; /* the files to be added */ + char **fnames = filenames; + short flag; /* flag for deleting or adding */ + + parse_args(argv, db_dir, filenames, &flag); + + if (!filenames[0]) { + fprintf(stderr, "%s\n", usage); + return -1; + } + + parser_init(); + + build_db_filename(flag, db_dir, dbfilename); + + if (fresh) + unlink(dbfilename); + + if (flag & Delete) + while (*fnames) + delete_file(dbfilename, *fnames++); + else + while (*fnames) + add_file(dbfilename, *fnames++, fresh); + return 0; +} + +/* + * This routine parses the command line arguments. It parses + * the command line arguments. It returns a flag which tells the calling + * routine what database file to use, and whether or not to delete files. + */ + + +static void +parse_args(char **argv, char *db_dir, char **filenames, short *fl) +{ + *fl = 0; + + while (*++argv) { + if (!strcmp(*argv, "-d")) + *fl |= Delete; + else if (!strcmp(*argv, "-s")) { + if (*fl & Current || *fl & Named) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= System; + } + else if (!strcmp(*argv, "-n")) { + fresh = 1; + } + else if (!strcmp(*argv, "-l")) { + if (*fl & System || *fl & Named) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= Current; + } + else if (!strcmp(*argv, "-f")) { + if (*fl & System || *fl & Current) { + fprintf(stderr, "%s\n", usage); + exit(-1); + } + *fl |= Named; + strcpy(db_dir, *++argv); + } + else + *filenames++ = *argv; + } + + *filenames = NULL; +} + + + +static int +writable(struct stat buff) +{ +#ifdef DEBUG + unsigned short uid = geteuid(), gid = getegid(); + + fprintf(stderr, "Uid = %d and Gid = %d\n", uid, gid); +#endif + + /* + * Checks the status structure sent against the user id, and goup id + */ + if ((buff.st_uid == geteuid()) && (buff.st_mode & S_IWUSR)) + return 1; + else if ((buff.st_gid == getegid()) && (buff.st_mode & S_IWGRP)) + return 1; + else if ((buff.st_mode & S_IWOTH)) + return 1; + return 0; +} + +/* check to see if the user has permission */ + +/* + * This procedure builds the db filename. Subsequently, it is passed onto all + * the add files that are called. + */ + + +static int +build_db_filename(short flag, char *db_dir, char *dbfilename) +{ + int ret_status; + struct stat buff; + char *SPAD; + char path[256]; + + + if (flag & System) { + SPAD = (char *) getenv("AXIOM"); + if (SPAD == NULL) { + fprintf(stderr, + "Build_db_filename: Defaulting on $AXIOM\n"); + SPAD = (char *) def_spad; + } + sprintf(dbfilename, "%s/share/hypertex/pages/%s", SPAD, db_file_name); + sprintf(path, "%s/share/hypertex/pages", SPAD); + } + else if (flag & Named) { + sprintf(dbfilename, "%s/%s", db_dir, db_file_name); + strcpy(path, db_dir); + } + else { /* use the current directory */ + sprintf(dbfilename, "./%s", db_file_name); + sprintf(path, "./"); + } +/* fprintf(stderr,"htadd:build_db_filename:dbfilename=%s\n",dbfilename);*/ + /* Now see if I can write to the file */ + ret_status = stat(dbfilename, &buff); + if (ret_status == -1) { + if (errno == ENOENT) { + /* If the file does not exist, then check it's path */ + ret_status = stat(path, &buff); + } + if (ret_status == -1) { + perror("build_db_file"); + exit(-1); + } + } + + /* check the status */ + + if (writable(buff)) + return 1; + + fprintf(stderr, "build_db_filename: Database file name is not writable\n"); + exit(-1); + return 0; +} + + +/*** + + This procedure now works as follows: + (1) It adds the files to the db_file without full pathnames. + Two names are going to be used when adding a file - + addname <-- The name without any paths + fullname <-- The name with a path prepended to it + (2) If the user specifies a pathname, then it is the path name that + is used. If the user does not dpecify a path name, then possible + paths are found as follows: + (i) If the user has an environment variable HTPATH set, the + paths mentioned are used. + (ii) If not, then the $AXIOM environment variable is used. +****/ + +static void +add_file(char *dbname, char *name, int fresh) +{ + char fullname[256]; + char temp_db_file[256]; + FILE *db_fp = NULL; + FILE *temp_db_fp = NULL; + FILE *ht_fp = NULL; + char addname[100]; + /*char *HTPATH;*/ + /*char *trace;*/ + /*char *spad;*/ + + + /** First thing I should do is find the proper file and open it **/ + ht_fp = ht_file_open(fullname, addname, name); + + /* + * Now I should try to open the two database files. The one to work with, + * and the temporary one; Send it a 1 so it checks for write access + */ + if (fresh) { + if ((db_fp = fopen(dbname, "a")) == NULL) { + fprintf(stderr, "Can't open database: %s file for appending\n", dbname); + exit(-1); + } + } + else { + if ((db_fp = fopen(dbname, "r")) == NULL) { + } + } + if (!fresh) + temp_db_fp = temp_file_open(temp_db_file); + + /** Now actually update the file by adding the changes ***/ + update_db(db_fp, temp_db_fp, ht_fp, addname, fullname, fresh); + + if (!fresh) + fclose(temp_db_fp); + fclose(ht_fp); + if (db_fp != NULL) + fclose(db_fp); + if (!fresh) { + copy_file(temp_db_file, dbname); + unlink(temp_db_file); + } +} + +static void +update_db(FILE *db, FILE *temp_db, FILE *new_file, + char *addname, char *fullname, int fresh) +{ + char *fname; + int c, file_there = 0, mtime; + + if (fresh) { + add_new_pages(db, new_file, addname, fullname); + return; + } + if (db == NULL) { + add_new_pages(temp_db, new_file, addname, fullname); + return; + } + init_scanner(); + cfile = db; + c = get_char(); + do { + if (c == '\t') { + get_filename(); + fname = alloc_string(token.id); + get_token(); + mtime = atoi(token.id); + if (strcmp(fname, addname) == 0) { + save_scanner_state(); + add_new_pages(temp_db, new_file, addname, fullname); + restore_scanner_state(); + file_there = 1; + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + } + } + else { + fprintf(temp_db, "\t%s %d", fname, mtime); + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + putc(c, temp_db); + } + } + free(fname); + } + else + c = get_char(); + } while (c != EOF); + if (!file_there) { + add_new_pages(temp_db, new_file, addname, fullname); + } +} + +#define Special(t) (( t == Page || t == NewCommand || t == Patch )?(1):(0)) +#define ptype(c, t) (strcpy(c, t)); + +static void +add_new_pages(FILE *temp_db, FILE *new_file, char *addname, char *fullname) +{ + char type[15]; + int pos; + int present_type; + int pages = 0; + struct stat fstats; + + stat(fullname, &fstats); + fprintf(temp_db, "\t%s %d\n", addname, (int)fstats.st_mtime); + cfile = new_file; + init_scanner(); + while (get_token() != EOF) { + if (Special(token.type)) { + ptype(type, token.id); + present_type = token.type; + pos = keyword_fpos; + get_token(); + if (token.type != Lbrace) { + fprintf(stderr, "missing left brace after a page, macro or patch \ + declaration\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + get_token(); + if (present_type == Page && token.type != Word) { + fprintf(stderr, "missing page name after \\begin{page}\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + else if (present_type == Macro && token.type != Macro) { + fprintf(stderr, "Expected a \\macro name after newcommand, got %s\n", + token.id); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + else if (present_type == Patch && token.type != Word) { + fprintf(stderr, "Missing patch name after a \\begin{patch}\n"); + fprintf(stderr, "In the file %s on line %d\n", fullname, line_number); + exit(-1); + } + fprintf(temp_db, "\\%s %s %d %d\n", type, + token.id, pos, line_number); + pages++; + } + } + printf("Added %3d pages and/or macros from %s\n", pages, addname); +} + +static void +copy_file(char *f1, char *f2) +{ + FILE *fp1, *fp2; + int c; + + fp1 = fopen(f1, "r"); + fp2 = fopen(f2, "w"); + while ((c = getc(fp1)) != EOF) { + putc(c, fp2); + } + fclose(fp2); + fclose(fp1); +} + + + +#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define delim(c) \ + (whitespace(c) ) + + +static void +get_filename(void) +{ + int c, ws; + static char buffer[256]; + char *buf = buffer; + + do { + keyword_fpos = fpos; + c = get_char(); + ws = whitespace(c); + } while (ws); + switch (c) { + case EOF: + fprintf(stderr, "Error trying to read ht.db, unexpected EOF\n"); + exit(-1); + case '%': + case '\\': + case '{': + case '}': + fprintf(stderr, "Error unexpexted character %c\n",c); + exit(-1); + default: + do { + *buf++ = c; + } while ((c = get_char()) != EOF && !delim(c)); + unget_char(c); + *buf = '\0'; + token.type = Word; + token.id = buffer; + break; + } +} + +static int +delete_file(char *dbname, char *name) +{ + char temp_db_file[256]; + FILE *db_fp, *temp_db_fp; + char dname[256]; + + + strcpy(dname, name); + extend_ht(dname); + + /* Open both the tmp database and the real one */ + if ((db_fp = fopen(dbname, "r")) == NULL) { + fprintf(stderr, "database file is empty, nothing to delete\n"); + return 1; + } + + temp_db_fp = temp_file_open(temp_db_file); + + /** Now actually update the file by deleting the pages */ + delete_db(db_fp, temp_db_fp, dname); + + fclose(temp_db_fp); + if (db_fp != NULL) + fclose(db_fp); + copy_file(temp_db_file, dbname); + unlink(temp_db_file); + return 0; +} + +static void +delete_db(FILE *db, FILE *temp_db, char *name) +{ + char *fname; + int c/*, file_there = 0*/, mtime; + + init_scanner(); + cfile = db; + c = get_char(); + do { + if (c == '\t') { + get_filename(); + fname = alloc_string(token.id); + get_token(); + mtime = atoi(token.id); + if (strcmp(fname, name) == 0) { + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + } + } + else { + fprintf(temp_db, "\t%s %d", fname, mtime); + while ((c = get_char()) != EOF) { + if (c == '\t') + break; + putc(c, temp_db); + } + } + free(fname); + } + else + c = get_char(); + } while (c != EOF); +} |