/* * rdf-tree.c - Retrieve statements from persistent Redland storage. * * Copyright (C) 2003-2004 Morten Frederiksen - http://purl.org/net/morten/ * * and * * Copyright (C) 2000-2006, David Beckett http://purl.org/net/dajobe/ * Copyright (C) 2000-2004, University of Bristol, UK http://www.bristol.ac.uk/ * * This package is Free Software and part of Redland http://librdf.org/ * * It is licensed under the following three licenses as alternatives: * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version * 2. GNU General Public License (GPL) V2 or any newer version * 3. Apache License, V2.0 or any newer version * * You may not use this file except in compliance with at least one of * the above three licenses. * * See LICENSE.html or LICENSE.txt at the top of this package for the * complete terms and further detail along with the license texts for * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively. * */ #include #include #include #include #include #include const char *VERSION = "0.4"; struct options { librdf_node *context; char *database; char *directory; char *host; char *model; int level; int port; char *output; char *password; int quiet; char *user; } opts; int main(int argc, char *argv[]); int tree(librdf_world * world, librdf_node * node, librdf_model * model, librdf_model * outputmodel, LHASH * table, int level); void hash_free(void *data); int getoptions(int argc, char *argv[], librdf_world * world); int usage(char *argv0, int version); int main(int argc, char *argv[]) { /* Redland objects. */ librdf_world *world; librdf_storage *storage; librdf_model *model; librdf_uri *uri = 0; librdf_storage *outputstorage; librdf_model *outputmodel; librdf_storage *contextstorage; librdf_model *contextmodel; librdf_stream *stream; librdf_serializer *serializer; int argnum; char *storage_type; char *storage_options; /* Create rdflib world. */ world = librdf_new_world(); if(!world) { fprintf(stderr, "%s: Failed to create Redland world\n", argv[0]); return (1); }; librdf_world_open(world); /* Parse command line options (if possible). */ argnum = getoptions(argc, argv, world); /* Check for URI argument. */ if(argnum < argc) { uri = librdf_new_uri(world, argv[argnum]); if(!uri) { fprintf(stderr, "%s: Failed to create input uri\n", argv[0]); exit(1); }; }; /* Set storage options. */ if(opts.database) { storage_type = strdup("mysql"); storage_options = malloc(strlen(opts.host) + strlen(opts.database) + strlen(opts.user) + strlen(opts.password) + 120); if(!storage_type || !storage_options) { fprintf(stderr, "%s: Failed to create 'mysql' storage options\n", argv[0]); return (1); }; sprintf(storage_options, "host='%s',database='%s',port='%i',user='%s',password='%s',contexts='yes',write='no'", opts.host, opts.database, opts.port, opts.user, opts.password); } else { storage_type = strdup("hashes"); storage_options = malloc(strlen(opts.directory) + 120); if(!storage_type || !storage_options) { fprintf(stderr, "%s: Failed to create 'hashes' storage options\n", argv[0]); return (1); }; sprintf(storage_options, "hash-type='bdb',dir='%s',contexts='yes',write='no'", opts.directory); }; /* Create storage. */ storage = librdf_new_storage(world, storage_type, opts.model, storage_options); if(!storage) { fprintf(stderr, "%s: Failed to create storage (%s/%s/%s)\n", argv[0], storage_type, opts.model, storage_options); return (1); } /* Create model. */ model = librdf_new_model(world, storage, NULL); if(!model) { fprintf(stderr, "%s: Failed to create model\n", argv[0]); return (1); } /* Create output storage. */ outputstorage = librdf_new_storage(world, "memory", "output", ""); if(!outputstorage) { fprintf(stderr, "%s: Failed to create output storage\n", argv[0]); return (1); } /* Create output model. */ outputmodel = librdf_new_model(world, outputstorage, NULL); if(!outputmodel) { fprintf(stderr, "%s: Failed to create output model\n", argv[0]); return (1); } /* Create serializer. */ serializer = librdf_new_serializer(world, opts.output, NULL, NULL); if(!serializer) { fprintf(stderr, "%s: Failed to create serializer\n", argv[0]); return (1); } if(librdf_model_size(model) != -1 && !opts.quiet) fprintf(stderr, "%s: Model '%s' contains %d statements.\n", argv[0], opts.model, librdf_storage_size(storage)); /* stream=librdf_model_as_stream(model); while (!librdf_stream_end(stream)) { librdf_statement *s; librdf_node *n; s=librdf_stream_get_object(stream); fprintf(stderr,"%s\n",librdf_statement_to_string(s)); n=librdf_stream_get_context(stream); fprintf(stderr,"- context: %s\n",n?librdf_node_to_string(n):"-"); librdf_stream_next(stream); }; librdf_free_stream(stream); */ /* Only statements with given context? */ if(opts.context) { if(!opts.quiet) fprintf(stderr, "%s: Creating context storage...\n", argv[0]); /* Create context storage. */ contextstorage = librdf_new_storage(world, "memory", "context", ""); if(!contextstorage) { fprintf(stderr, "%s: Failed to create context storage\n", argv[0]); return (1); }; /* Create context model. */ contextmodel = librdf_new_model(world, contextstorage, NULL); if(!contextmodel) { fprintf(stderr, "%s: Failed to create context model\n", argv[0]); return (1); }; /* Extract statements with given context. */ if(!(stream = librdf_model_context_as_stream(model, opts.context))) { fprintf(stderr, "%s: Failed to serialize context model\n", argv[0]); return (1); }; if(librdf_model_add_statements(contextmodel, stream)) { fprintf(stderr, "%s: Failed to add statements to context model\n", argv[0]); return (1); }; librdf_free_model(model); librdf_free_storage(storage); storage = contextstorage; model = contextmodel; }; /* Populate output model... */ if(uri) { int rc = 0; LHASH *table = lh_new((LHASH_HASH_FN_TYPE) lh_strhash, (LHASH_COMP_FN_TYPE) strcmp); if(!table) { fprintf(stderr, "%s: Failed to create hash table\n", argv[0]); return (1); }; if(!opts.quiet) fprintf(stderr, "%s: Populating output model from uri...\n", argv[0]); /* Recursively extract statements about subject... */ rc = tree(world, librdf_new_node_from_uri(world, uri), model, outputmodel, table, opts.level); lh_doall(table, (LHASH_DOALL_FN_TYPE) hash_free); lh_free(table); if(rc) { fprintf(stderr, "%s: Failed to extract statements from model (%d)\n", argv[0], rc); return (1); }; librdf_free_model(model); librdf_free_storage(storage); } else { if(!opts.quiet) fprintf(stderr, "%s: Outputting entire model...\n", argv[0]); /* No restraints, use entire model as output. */ librdf_free_model(outputmodel); librdf_free_storage(outputstorage); outputstorage = storage; outputmodel = model; }; /* Serialize output... */ if(!opts.quiet) fprintf(stderr, "%s: Serializing...\n", argv[0]); if(librdf_serializer_serialize_model(serializer, stdout, NULL, outputmodel)) { fprintf(stderr, "%s: Failed to serialize output model\n", argv[0]); return (1); }; /* Clean up. */ librdf_free_serializer(serializer); librdf_free_model(outputmodel); librdf_free_storage(outputstorage); librdf_free_world(world); /* keep gcc -Wall happy */ return (0); } int tree(librdf_world * world, librdf_node * node, librdf_model * model, librdf_model * outputmodel, LHASH * table, int level) { librdf_stream *instream; librdf_node *object; librdf_statement *statement; int rc; librdf_node_type ont; librdf_node *rdftype = librdf_new_node_from_uri_string(world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); /* Add node to hash, to prevent cycles. */ lh_insert(table, strdup(librdf_node_to_string(node))); if(lh_error(table)) { return 1; } /* Find all statements about node. */ if(! (statement = librdf_new_statement_from_nodes(world, librdf_new_node_from_node(node), NULL, NULL))) { return 2; } if(!(instream = librdf_model_find_statements(model, statement))) { return 0; } while(!librdf_stream_end(instream)) { /* Add statement to output model. */ statement = librdf_stream_get_object(instream); if(librdf_model_add_statement(outputmodel, librdf_new_statement_from_statement (statement))) return 4; /* Recurse? */ if(level && !librdf_node_equals(rdftype, librdf_statement_get_predicate (statement))) { object = librdf_statement_get_object(statement); ont = librdf_node_get_type(object); if(ont == LIBRDF_NODE_TYPE_RESOURCE || ont == LIBRDF_NODE_TYPE_BLANK) { /* librdf_statement_print(statement,stderr); fprintf(stderr,"%s","\n"); */ /* Don't recurse if object is known... */ if(!lh_retrieve(table, librdf_node_to_string(object))) { rc = tree(world, object, model, outputmodel, table, level - 1); if(rc) return rc; } }; }; librdf_stream_next(instream); }; librdf_free_stream(instream); return 0; }; void hash_free(void *data) { free(data); }; int getoptions(int argc, char *argv[], librdf_world * world) { /* Define command line options. */ struct option opts_long[] = { {"help", no_argument, NULL, '?'}, {"context", required_argument, NULL, 'c'}, {"database", required_argument, NULL, 's'}, {"directory", required_argument, NULL, 'd'}, {"host", required_argument, NULL, 'h'}, {"level", required_argument, NULL, 'l'}, {"model", required_argument, NULL, 'm'}, {"output", required_argument, NULL, 'o'}, {"port", required_argument, NULL, 'P'}, {"password", optional_argument, NULL, 'p'}, {"quiet", no_argument, NULL, 'q'}, {"user", required_argument, NULL, 'u'}, {"version", no_argument, NULL, 'v'}, {0, 0, 0, 0} }; const char *opts_short = "?c:D:d:h:l:m:o:P:p:qu:v"; int i = 1; char c; char *buffer; int ttypasswd = 1; /* Set defaults. */ opts.context = 0; opts.level = 1; opts.password = 0; opts.port = 3306; opts.quiet = 0; opts.user = 0; if(!(opts.directory = strdup("./")) || !(opts.host = strdup("mysql")) || !(opts.model = strdup("redland")) || !(opts.output = strdup("rdfxml")) || !(opts.database = strdup("redland"))) { fprintf(stderr, "%s: Failed to allocate default options\n", argv[0]); exit(1); }; while((c = getopt_long(argc, argv, opts_short, opts_long, &i)) != -1) { if(optarg) { buffer = malloc(strlen(optarg) + 1); if(!buffer) { fprintf(stderr, "%s: Failed to allocate buffer for command line argument (%s)\n", argv[0], optarg); exit(1); }; strncpy(buffer, optarg, strlen(optarg) + 1); }; switch (c) { case '?': usage(argv[0], 0); case 'c': free(buffer); opts.context = librdf_new_node_from_uri_string(world, optarg); if(!opts.context) { fprintf(stderr, "%s: Failed to create context node (%s)\n", argv[0], optarg); exit(1); }; break; case 'D': free(opts.directory); opts.directory = 0; opts.database = buffer; break; case 'd': free(opts.database); opts.database = 0; opts.directory = buffer; break; case 'h': opts.host = buffer; break; case 'l': free(buffer); opts.level = atoi(optarg); break; case 'm': opts.model = buffer; break; case 'o': free(opts.output); opts.output = buffer; break; case 'P': free(buffer); opts.port = atoi(optarg); break; case 'p': opts.password = buffer; ttypasswd = 0; break; case 'q': opts.quiet = 1; break; case 'u': opts.user = buffer; break; case 'v': usage(argv[0], 1); default: fprintf(stderr, "%s: Invalid option (%c)\n", argv[0], c); usage(argv[0], 0); } } /* Flag missing user name. */ if(opts.database && !opts.user) { fprintf(stderr, "%s: Missing user name for mysql storage\n", argv[0]); usage(argv[0], 0); exit(1); }; /* Read password from tty if not specified. */ if(opts.database && ttypasswd) { char c2; int i2 = 0; opts.password = malloc(128); if(!opts.password) { fprintf(stderr, "%s: Failed to allocate buffer for password\n", argv[0]); exit(1); }; fprintf(stderr, "%s: Enter password for %s@%s/%s: ", argv[0], opts.user, opts.host, opts.database); while((c2 = getchar()) != '\n') { opts.password[i2++] = c2; if(i2 == 127) break; }; opts.password[i2++] = 0; }; return optind; } int usage(char *argv0, int version) { printf("\n\ %s Version %s\n\ Retrieve statements from persistent Redland storage.\n\ * Copyright (C) 2003 Morten Frederiksen - http://purl.org/net/morten/\n\ * Copyright (C) 2000-2003 David Beckett - http://purl.org/net/dajobe/\n\ ", argv0, VERSION); if(version) exit(0); printf("\n\ usage: %s [options] [ ]\n\ \n\ -?, --help Display this help message and exit.\n\ -c, --context=\n\ Extract only statements with given context URI.\n\ -D, --database=\n\ Name of MySQL database to use, default is 'redland'.\n\ -d, --directory=\n\ Directory to use for BDB files. When provided implies use\n\ of 'hashes' storage type instead of 'mysql'.\n\ -h, --host=\n\ Host to contact for MySQL connections, default is 'mysql'.\n\ -l, --level=\n\ The number of levels of statements to extract. Default is\n\ 1, also returning statements about objects.\n\ -m, --model=\n\ Identifier for (name of) storage (model name for storage\n\ type 'mysql', base file name for storage type 'hashes'),\n\ default is 'redland'.\n\ -o, --output=\n\ Syntax identifier for serialization, 'ntriples' or\n\ 'rdfxml' (default).\n\ -p, --password=\n\ Password to use when connecting to MySQL server.\n\ If password is not given it's asked from the tty.\n\ -P, --port=\n\ The port number to use when connecting to MySQL server.\n\ Default port number is 3306.\n\ -q, --quiet\n\ No informational messages, only errors.\n\ -u, --user=\n\ User name for MySQL server.\n\ -v, --version Output version information and exit.\n\ \n\ ", argv0); exit(1); }