Initial comit - Clone
This commit is contained in:
11
.git-blame-ignore-revs
Normal file
11
.git-blame-ignore-revs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Use `git config blame.ignoreRevsFile .git-blame-ignore-revs`
|
||||||
|
# to make git blame ignore commits in this file
|
||||||
|
|
||||||
|
#First ocamlformat commit:
|
||||||
|
a1f95e70a530ea60ee4a13715eb52f06a7a02710
|
||||||
|
|
||||||
|
#ocamlformat sosa_(array|num)
|
||||||
|
da7c849491f10f9c723b0bf6020a87026ca3f7ec
|
||||||
|
|
||||||
|
#Switch to standard ocaml syntax and use jbuilder:
|
||||||
|
94c6b620af7d225505102554faea1a1d262e3272
|
28
.gitattributes
vendored
Normal file
28
.gitattributes
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||||
|
# Explicitly declare text files you want to always be normalized and converted
|
||||||
|
# to native line endings on checkout.
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.config text
|
||||||
|
*.cgi text
|
||||||
|
*.css text
|
||||||
|
*.gw text
|
||||||
|
*.gwf text
|
||||||
|
*.htm text
|
||||||
|
*.html text
|
||||||
|
*.in text
|
||||||
|
*.iss text eol=crlf
|
||||||
|
*.js text
|
||||||
|
*.md text
|
||||||
|
*.ml text
|
||||||
|
*.mli text
|
||||||
|
*.opam text
|
||||||
|
*.sh text
|
||||||
|
*.txt text
|
||||||
|
*.1 text
|
||||||
|
|
||||||
|
# Denote all files that are truly binary and should not be modified.
|
||||||
|
*.bmp binary
|
||||||
|
*.ico binary
|
||||||
|
*.icns binary
|
||||||
|
*.jpg binary
|
||||||
|
*.png binary
|
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug / Description du bogue**
|
||||||
|
|
||||||
|
A clear and concise description of what the bug is and how to reproduce it.
|
||||||
|
Adding a failing unit test showing the error would be appreciate.
|
||||||
|
Do not hesitate to add screenshots.
|
||||||
|
|
||||||
|
Une définition claire et concise du bogue, ainsi que la description de la
|
||||||
|
manière de le reproduire.
|
||||||
|
Des screenshots peuvent aider à la compréhension du problème.
|
||||||
|
|
||||||
|
**Expected behavior / Comportement attendu**
|
||||||
|
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
Une définition claire et concise de ce qui était attendu.
|
||||||
|
|
||||||
|
**Versions**
|
||||||
|
|
||||||
|
Version of packages used to reproduce the bug.
|
||||||
|
|
||||||
|
Les versions des paquets utilisés pour reproduire le bug.
|
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea
|
||||||
|
title: "[FEATURE REQUEST]"
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
7
.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
name: Other
|
||||||
|
about: Anything that is neither a bug report nor a feature request
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
14
.github/dependabot.yml
vendored
Normal file
14
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
directory: "docker/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "gitsubmodule"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: ".github/workflows/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
44
.github/workflows/ci.yml
vendored
Normal file
44
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
name: build
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- macos-latest
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
|
ocaml-compiler:
|
||||||
|
- 4.14.x
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
ocaml-version: 4.08.0
|
||||||
|
- os: ubuntu-latest
|
||||||
|
ocaml-version: 5.1.x
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Use Ocaml ${{ matrix.ocaml-compiler }}
|
||||||
|
uses: ocaml/setup-ocaml@v2
|
||||||
|
with:
|
||||||
|
ocaml-compiler: ${{ matrix.ocaml-compiler }}
|
||||||
|
- name: Setup GeneWeb dependencies + ocamlformat
|
||||||
|
run: |
|
||||||
|
opam pin add . -y --no-action
|
||||||
|
opam depext -y geneweb
|
||||||
|
opam install -y ./*.opam --deps-only --with-test
|
||||||
|
opam pin ocamlformat 0.24.1
|
||||||
|
- name: Make ocamlformat > build > distrib
|
||||||
|
run: |
|
||||||
|
opam exec -- ocaml ./configure.ml --release
|
||||||
|
opam exec -- make build distrib
|
||||||
|
- name: Make CI tests
|
||||||
|
run: opam exec -- make ci
|
29
.github/workflows/doc.yml
vendored
Normal file
29
.github/workflows/doc.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: deploy-doc
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout-code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: setup-ocaml
|
||||||
|
uses: ocaml/setup-ocaml@v2
|
||||||
|
with:
|
||||||
|
ocaml-compiler: 4.14.0
|
||||||
|
- name: setup
|
||||||
|
run: |
|
||||||
|
opam pin add . -y --no-action
|
||||||
|
opam depext -y geneweb
|
||||||
|
opam install -y ./*.opam --deps-only --with-doc
|
||||||
|
- name: build
|
||||||
|
run: |
|
||||||
|
opam exec -- ocaml ./configure.ml
|
||||||
|
opam exec -- make doc
|
||||||
|
- name: deploy
|
||||||
|
uses: JamesIves/github-pages-deploy-action@v4
|
||||||
|
with:
|
||||||
|
branch: gh-pages # The branch the action should deploy to.
|
||||||
|
folder: _build/default/_doc/_html # The folder the action should deploy.
|
76
.github/workflows/docker.yml
vendored
Normal file
76
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
name: Build Docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Allow manual runs.
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- '**/*.md'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**/*.md'
|
||||||
|
|
||||||
|
env:
|
||||||
|
PLATFORMS: linux/arm64/v8,linux/amd64
|
||||||
|
IMAGE_NAME: "geneweb"
|
||||||
|
PUSH_IMAGE: ${{ github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build-images:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Generate date stamp
|
||||||
|
run: echo "DATESTAMP=$(date +"%Y.%m.%d")" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Generate Docker image metadata
|
||||||
|
id: docker-meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
||||||
|
# ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=edge,branch=master
|
||||||
|
type=raw,${{ env.DATESTAMP }}
|
||||||
|
type=ref,event=tag
|
||||||
|
type=sha,prefix=,format=short
|
||||||
|
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Setup Docker BuildKit
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
# - name: Login to DockerHub
|
||||||
|
# if: ${{ env.PUSH_IMAGE == 'true' }}
|
||||||
|
# uses: docker/login-action@v2
|
||||||
|
# with:
|
||||||
|
# username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
# password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
if: ${{ env.PUSH_IMAGE == 'true' }}
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Build and push ${{ env.IMAGE_NAME }} Docker image
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
target: container
|
||||||
|
context: docker/
|
||||||
|
file: docker/Dockerfile
|
||||||
|
platforms: ${{ env.PLATFORMS }}
|
||||||
|
push: ${{ env.PUSH_IMAGE }}
|
||||||
|
tags: ${{ steps.docker-meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker-meta.outputs.labels }}
|
69
.github/workflows/release.yml
vendored
Normal file
69
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
release:
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
|
||||||
|
include:
|
||||||
|
- os: macos-latest
|
||||||
|
ocaml-version: 4.14.0
|
||||||
|
geneweb-archive: geneweb-macos.zip
|
||||||
|
- os: ubuntu-latest
|
||||||
|
ocaml-version: 4.14.0
|
||||||
|
geneweb-archive: geneweb-linux.zip
|
||||||
|
- os: windows-latest
|
||||||
|
ocaml-version: 4.14.0
|
||||||
|
geneweb-archive: geneweb-windows.zip
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: setup-ocaml
|
||||||
|
uses: ocaml/setup-ocaml@v2
|
||||||
|
with:
|
||||||
|
ocaml-compiler: ${{ matrix.ocaml-version }}
|
||||||
|
|
||||||
|
- name: setup
|
||||||
|
run: |
|
||||||
|
opam install dune ocamlformat.0.24.1
|
||||||
|
opam exec -- dune build @fmt
|
||||||
|
opam pin add . -y --no-action
|
||||||
|
opam depext -y geneweb
|
||||||
|
opam install -y ./*.opam --deps-only --with-test
|
||||||
|
|
||||||
|
# Build the distribution
|
||||||
|
- name: Build the distribution
|
||||||
|
run: |
|
||||||
|
opam exec -- ocaml ./configure.ml --sosa-legacy --gwdb-legacy --release
|
||||||
|
opam exec -- make distrib
|
||||||
|
|
||||||
|
# Archive distribution for release
|
||||||
|
- name: Archive Release
|
||||||
|
uses: thedoctor0/zip-release@0.7.1
|
||||||
|
with:
|
||||||
|
type: zip
|
||||||
|
filename: ${{ matrix.geneweb-archive }}
|
||||||
|
directory: distribution
|
||||||
|
|
||||||
|
# Upload the distribution
|
||||||
|
- name: Upload distribution to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: distribution/${{ matrix.geneweb-archive }}
|
||||||
|
tag: ${{ github.ref }}
|
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
.merlin
|
||||||
|
|
||||||
|
distribution
|
||||||
|
|
||||||
|
Makefile.config
|
||||||
|
Makefile.local
|
||||||
|
|
||||||
|
# Generated from dune.in files
|
||||||
|
benchmark/dune
|
||||||
|
bin/cache_files/dune
|
||||||
|
bin/connex/dune
|
||||||
|
bin/consang/dune
|
||||||
|
bin/fixbase/dune
|
||||||
|
bin/ged2gwb/dune
|
||||||
|
bin/gwb2ged/dune
|
||||||
|
bin/gwc/dune
|
||||||
|
bin/gwd/dune
|
||||||
|
bin/gwdiff/dune
|
||||||
|
bin/gwgc/dune
|
||||||
|
bin/gwrepl/.depend
|
||||||
|
bin/gwrepl/dune
|
||||||
|
bin/gwu/dune
|
||||||
|
bin/setup/dune
|
||||||
|
bin/update_nldb/dune
|
||||||
|
lib/core/dune
|
||||||
|
lib/dune
|
||||||
|
lib/gwdb/dune
|
||||||
|
lib/util/dune
|
||||||
|
plugins/welcome/dune
|
||||||
|
test/dune
|
||||||
|
|
||||||
|
dune-workspace
|
||||||
|
|
||||||
|
# Generated by jbuilder
|
||||||
|
_build/
|
||||||
|
*.exe
|
||||||
|
*.bc
|
||||||
|
*.install
|
||||||
|
|
||||||
|
# generated by Makefile
|
||||||
|
hd/etc/version.txt
|
||||||
|
lib/version.ml
|
||||||
|
lib/gwlib.ml
|
||||||
|
*~
|
||||||
|
/_opam
|
2
.ocamlformat
Normal file
2
.ocamlformat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
profile = default
|
||||||
|
version = 0.24.1
|
7
.ocamlformat-ignore
Normal file
7
.ocamlformat-ignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
plugins/forum/plugin_forum.cppo.ml
|
||||||
|
bin/ged2gwb/ged2gwb.ml
|
||||||
|
bin/gwd/gwd.ml
|
||||||
|
bin/gwd/gwdLog.ml
|
||||||
|
bin/gwd/request.ml
|
||||||
|
bin/setup/setup.ml
|
||||||
|
lib/util/mutil.ml
|
37
CONTRIBUTING.md
Normal file
37
CONTRIBUTING.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
When contributing to this repository, please first discuss the change
|
||||||
|
you wish to make via issue, email, or any other method with the owners
|
||||||
|
of this repository before making a change.
|
||||||
|
|
||||||
|
## Pull request validation
|
||||||
|
|
||||||
|
When proposing a PR:
|
||||||
|
|
||||||
|
- Describe what problem it solves, what side effects come with it.
|
||||||
|
- Describe how to test the PR.
|
||||||
|
- Adding some screenshots will help.
|
||||||
|
- Add some documentation if relevant.
|
||||||
|
- Add some unit tests if relevant.
|
||||||
|
- Add some benchmarks if relevant.
|
||||||
|
- Add some comments around blocks/functions if relevant.
|
||||||
|
- Format your code with ocamlformat (use `make fmt`).
|
||||||
|
|
||||||
|
Some reasons why a PR could be refused:
|
||||||
|
|
||||||
|
- PR is not meeting one of the previous points.
|
||||||
|
- PR is not meeting
|
||||||
|
[milestones](https://github.com/geneweb/geneweb/milestones) goals.
|
||||||
|
- PR is conflicting with another PR, and the latter is being preferred.
|
||||||
|
- PR slows down GeneWeb, or it obviously does too many
|
||||||
|
computations for the task being accomplished. It needs to be
|
||||||
|
optimized.
|
||||||
|
- PR is using copy-n-paste programming. It needs to be factorized.
|
||||||
|
- PR contains commented code: remove it.
|
||||||
|
- PR adds new features or changes the behavior of GeneWeb without
|
||||||
|
having been approved by the current project owners first.
|
||||||
|
- PR is too big and needs to be split into many smaller ones.
|
||||||
|
- PR is not formatted with ocamlformat.
|
||||||
|
|
||||||
|
If a PR stays in a stale/WIP/POC state for too long, it may be closed
|
||||||
|
at any time.
|
59
INSTALL
Normal file
59
INSTALL
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
INSTALLATIONS INSTRUCTIONS IN UNIX or MACOSX MACHINES
|
||||||
|
|
||||||
|
For the compilation, you need the Objective Caml compiler installed
|
||||||
|
in your computer. The compilation works for several versions of ocaml.
|
||||||
|
You also need the preprocessor camlp5.
|
||||||
|
|
||||||
|
They freely distributed at address:
|
||||||
|
http://caml.inria.fr/ocaml/
|
||||||
|
http://pauillac.inria.fr/~ddr/camlp5/
|
||||||
|
|
||||||
|
1- In the top directory, do:
|
||||||
|
./configure
|
||||||
|
|
||||||
|
2- Do:
|
||||||
|
make
|
||||||
|
|
||||||
|
If your platform does not have the command ocamlopt, the
|
||||||
|
executables will be slower.
|
||||||
|
|
||||||
|
3- Do:
|
||||||
|
make distrib
|
||||||
|
|
||||||
|
This creates a directory "distribution" where all executables programs
|
||||||
|
and documentation are copied.
|
||||||
|
|
||||||
|
This can constitute a "distribution" directory if you want to distribute
|
||||||
|
executables.
|
||||||
|
|
||||||
|
4- To use GeneWeb, move the directory "distribution" to another place, or
|
||||||
|
rename it.
|
||||||
|
On macOSX, do:
|
||||||
|
make install
|
||||||
|
This will install the distribution folder on your Desktop and rename it "GeneWeb-7.00-Mac"
|
||||||
|
(or another name of your choice).
|
||||||
|
|
||||||
|
Go to this directory and launch the commands "./gwd" and possibly "./gwsetup".
|
||||||
|
On macOSX, geneweb.command will kill previous instances, launch both gwd and gwsetup
|
||||||
|
and minimize the window.
|
||||||
|
|
||||||
|
The reason why it is much better to move this directory is that "make clean"
|
||||||
|
deletes it, and another "make distrib" overwrites it. If you created
|
||||||
|
genealogic databases inside, they would be deleted.
|
||||||
|
|
||||||
|
|
||||||
|
INSTALLATIONS INSTRUCTIONS IN WINDOWS NT/95/98
|
||||||
|
|
||||||
|
You need:
|
||||||
|
|
||||||
|
- The Cygnus GNU-Win32 development tool, free (search in the Web)
|
||||||
|
|
||||||
|
- The Microsoft Visual C++ compiler.
|
||||||
|
|
||||||
|
- The Microsoft Assembler masm.
|
||||||
|
|
||||||
|
- The Objective Caml compiler.
|
||||||
|
|
||||||
|
- The Camlp5 preprocessor.
|
||||||
|
|
||||||
|
Follow the same instructions above than for the Unix installation.
|
340
LICENSE
Normal file
340
LICENSE
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
260
Makefile
Normal file
260
Makefile
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
ifneq ($(MAKECMDGOALS),ci)
|
||||||
|
Makefile.config: configure.ml
|
||||||
|
@if [ -e "$@" ]; then \
|
||||||
|
echo "configure file has changed. Please rerun ocaml ./configure.ml"; exit 1; \
|
||||||
|
else \
|
||||||
|
echo "Please run ocaml ./configure.ml first"; exit 1; \
|
||||||
|
fi
|
||||||
|
include Makefile.config
|
||||||
|
endif
|
||||||
|
|
||||||
|
-include Makefile.local
|
||||||
|
|
||||||
|
# Variables for packagers.
|
||||||
|
DISTRIB_DIR=distribution
|
||||||
|
BUILD_DIR=_build/default
|
||||||
|
BUILD_DISTRIB_DIR=$(BUILD_DIR)/bin/
|
||||||
|
ODOC_DIR=$(BUILD_DIR)/_doc/_html
|
||||||
|
|
||||||
|
# [BEGIN] Generated files section
|
||||||
|
|
||||||
|
CPPO_D=$(GWDB_D) $(OS_D) $(SYSLOG_D) $(SOSA_D)
|
||||||
|
|
||||||
|
ifeq ($(DUNE_PROFILE),dev)
|
||||||
|
CPPO_D+= -D DEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
%/dune: %/dune.in Makefile.config
|
||||||
|
@printf "Generating $@…" \
|
||||||
|
&& cat $< \
|
||||||
|
| cppo -n $(CPPO_D) \
|
||||||
|
| sed \
|
||||||
|
-e "s/%%%CPPO_D%%%/$(CPPO_D)/g" \
|
||||||
|
-e "s/%%%SOSA_PKG%%%/$(SOSA_PKG)/g" \
|
||||||
|
-e "s/%%%GWDB_PKG%%%/$(GWDB_PKG)/g" \
|
||||||
|
-e "s/%%%SYSLOG_PKG%%%/$(SYSLOG_PKG)/g" \
|
||||||
|
-e "s/%%%DUNE_DIRS_EXCLUDE%%%/$(DUNE_DIRS_EXCLUDE)/g" \
|
||||||
|
> $@ \
|
||||||
|
&& printf " Done.\n"
|
||||||
|
|
||||||
|
bin/gwrepl/.depend:
|
||||||
|
@printf "Generating $@…"
|
||||||
|
@pwd > $@
|
||||||
|
@dune top bin/gwrepl >> $@
|
||||||
|
@printf " Done.\n"
|
||||||
|
|
||||||
|
dune-workspace: dune-workspace.in Makefile.config
|
||||||
|
@cat $< | sed -e "s/%%%DUNE_PROFILE%%%/$(DUNE_PROFILE)/g" > $@
|
||||||
|
|
||||||
|
COMPIL_DATE := $(shell date +'%Y-%m-%d')
|
||||||
|
COMMIT_DATE := $(shell git show -s --date=short --pretty=format:'%cd')
|
||||||
|
COMMIT_ID := $(shell git rev-parse --short HEAD)
|
||||||
|
COMMIT_MSG := $(shell git log -1 --pretty="%s%n%n%b" | sed 's/"/\\"/g')
|
||||||
|
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
VERSION := $(shell awk -F\" '/er =/ {print $$2}' lib/version.txt)
|
||||||
|
SOURCE := $(shell git remote get-url origin | sed -n 's|^.*m/\([^/]\+/[^/.]\+\)\(.git\)\?|\1|p')
|
||||||
|
OCAMLV := $(shell ocaml --version)
|
||||||
|
|
||||||
|
lib/version.ml:
|
||||||
|
@cp lib/version.txt $@
|
||||||
|
@printf "let branch = \"$(BRANCH)\"\n" >> $@
|
||||||
|
@printf "let src = \"$(SOURCE)\"\n" >> $@
|
||||||
|
@printf "let commit_id = \"$(COMMIT_ID)\"\n" >> $@
|
||||||
|
@printf "let commit_date = \"$(COMMIT_DATE)\"\n" >> $@
|
||||||
|
@printf "let compil_date = \"$(COMPIL_DATE)\"\n" >> $@
|
||||||
|
@printf "Generating $@… Done.\n"
|
||||||
|
.PHONY: lib/version.ml
|
||||||
|
|
||||||
|
info:
|
||||||
|
@printf "Building \033[1;37mGeneweb $(VERSION)\033[0m with $(OCAMLV).\n\n"
|
||||||
|
@printf "Repository \033[1;37m$(SOURCE)\033[0m. Branch \033[1;37m$(BRANCH)\033[0m.\n\n"
|
||||||
|
@printf "Last commit \033[1;37m$(COMMIT_ID)\033[0m with message “\033[1;37m%s\033[0m”.\n" '$(subst ','\'',$(COMMIT_MSG))'
|
||||||
|
@printf "\n\033[1;37mGenerating configuration files\033[0m\n"
|
||||||
|
|
||||||
|
GENERATED_FILES_DEP = \
|
||||||
|
dune-workspace \
|
||||||
|
lib/version.ml \
|
||||||
|
lib/dune \
|
||||||
|
lib/gwdb/dune \
|
||||||
|
lib/core/dune \
|
||||||
|
lib/util/dune \
|
||||||
|
benchmark/dune \
|
||||||
|
bin/connex/dune \
|
||||||
|
bin/cache_files/dune \
|
||||||
|
bin/consang/dune \
|
||||||
|
bin/fixbase/dune \
|
||||||
|
bin/ged2gwb/dune \
|
||||||
|
bin/gwb2ged/dune \
|
||||||
|
bin/gwc/dune \
|
||||||
|
bin/gwd/dune \
|
||||||
|
bin/gwdiff/dune \
|
||||||
|
bin/gwgc/dune \
|
||||||
|
bin/gwrepl/dune \
|
||||||
|
bin/gwrepl/.depend \
|
||||||
|
bin/gwu/dune \
|
||||||
|
bin/setup/dune \
|
||||||
|
bin/update_nldb/dune \
|
||||||
|
test/dune \
|
||||||
|
|
||||||
|
generated: $(GENERATED_FILES_DEP)
|
||||||
|
|
||||||
|
install uninstall build distrib: info $(GENERATED_FILES_DEP)
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
$(RM) -r $(DISTRIB_DIR)
|
||||||
|
dune build @fmt --auto-promote
|
||||||
|
|
||||||
|
# [BEGIN] Installation / Distribution section
|
||||||
|
|
||||||
|
build: ## Build the geneweb package (libraries and binaries)
|
||||||
|
build:
|
||||||
|
ifneq ($(OS_TYPE),Win)
|
||||||
|
@printf "\n\033[1;37mOcamlformat\033[0m\n"
|
||||||
|
dune build @fmt --auto-promote
|
||||||
|
endif
|
||||||
|
@printf "\n\033[1;37mBuilding executables\033[0m\n"
|
||||||
|
dune build -p geneweb --profile $(DUNE_PROFILE)
|
||||||
|
|
||||||
|
install: ## Install geneweb using dune
|
||||||
|
install:
|
||||||
|
dune build @install --profile $(DUNE_PROFILE)
|
||||||
|
dune install
|
||||||
|
|
||||||
|
uninstall: ## Uninstall geneweb using dune
|
||||||
|
uninstall:
|
||||||
|
dune build @install --profile $(DUNE_PROFILE)
|
||||||
|
dune uninstall
|
||||||
|
|
||||||
|
distrib: build ## Build the project and copy what is necessary for distribution
|
||||||
|
distrib:
|
||||||
|
$(RM) -r $(DISTRIB_DIR)
|
||||||
|
@printf "\n\033[1;37mCreating distribution directory\033[0m\n"
|
||||||
|
mkdir $(DISTRIB_DIR)
|
||||||
|
mkdir -p $(DISTRIB_DIR)/bases
|
||||||
|
cp CHANGES $(DISTRIB_DIR)/CHANGES.txt
|
||||||
|
cp LICENSE $(DISTRIB_DIR)/LICENSE.txt
|
||||||
|
cp etc/README.txt $(DISTRIB_DIR)/.
|
||||||
|
cp etc/LISEZMOI.txt $(DISTRIB_DIR)/.
|
||||||
|
cp etc/START.htm $(DISTRIB_DIR)/.
|
||||||
|
ifeq ($(OS_TYPE),Win)
|
||||||
|
cp etc/Windows/gwd.bat $(DISTRIB_DIR)
|
||||||
|
cp etc/Windows/gwsetup.bat $(DISTRIB_DIR)
|
||||||
|
cp -f etc/Windows/README.txt $(DISTRIB_DIR)/README.txt
|
||||||
|
cp -f etc/Windows/LISEZMOI.txt $(DISTRIB_DIR)/LISEZMOI.txt
|
||||||
|
else ifeq ($(OS_TYPE),Darwin)
|
||||||
|
cp etc/gwd.sh $(DISTRIB_DIR)
|
||||||
|
cp etc/gwsetup.sh $(DISTRIB_DIR)
|
||||||
|
cp etc/macOS/geneweb.sh $(DISTRIB_DIR)
|
||||||
|
else
|
||||||
|
cp etc/gwd.sh $(DISTRIB_DIR)/gwd.sh
|
||||||
|
cp etc/gwsetup.sh $(DISTRIB_DIR)/gwsetup.sh
|
||||||
|
endif
|
||||||
|
mkdir $(DISTRIB_DIR)/gw
|
||||||
|
cp etc/a.gwf $(DISTRIB_DIR)/gw/.
|
||||||
|
echo "-setup_link" > $(DISTRIB_DIR)/gw/gwd.arg
|
||||||
|
@printf "\n\033[1;37m└ Copy binaries in $(DISTRIB_DIR)/gw/\033[0m\n"
|
||||||
|
cp $(BUILD_DISTRIB_DIR)connex/connex.exe $(DISTRIB_DIR)/gw/connex$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)consang/consang.exe $(DISTRIB_DIR)/gw/consang$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)fixbase/gwfixbase.exe $(DISTRIB_DIR)/gw/gwfixbase$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)ged2gwb/ged2gwb.exe $(DISTRIB_DIR)/gw/ged2gwb$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)gwb2ged/gwb2ged.exe $(DISTRIB_DIR)/gw/gwb2ged$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)cache_files/cache_files.exe $(DISTRIB_DIR)/gw/cache_files$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)gwc/gwc.exe $(DISTRIB_DIR)/gw/gwc$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)gwd/gwd.exe $(DISTRIB_DIR)/gw/gwd$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)gwdiff/gwdiff.exe $(DISTRIB_DIR)/gw/gwdiff$(EXT)
|
||||||
|
if test -f $(BUILD_DISTRIB_DIR)gwrepl/gwrepl.bc ; then cp $(BUILD_DISTRIB_DIR)gwrepl/gwrepl.bc $(DISTRIB_DIR)/gw/gwrepl$(EXT); fi
|
||||||
|
cp $(BUILD_DISTRIB_DIR)gwu/gwu.exe $(DISTRIB_DIR)/gw/gwu$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)setup/setup.exe $(DISTRIB_DIR)/gw/gwsetup$(EXT)
|
||||||
|
cp $(BUILD_DISTRIB_DIR)update_nldb/update_nldb.exe $(DISTRIB_DIR)/gw/update_nldb$(EXT)
|
||||||
|
@printf "\n\033[1;37m└ Copy templates in $(DISTRIB_DIR)/gw/\033[0m\n"
|
||||||
|
cp -R hd/* $(DISTRIB_DIR)/gw/
|
||||||
|
mkdir $(DISTRIB_DIR)/gw/setup
|
||||||
|
cp bin/setup/intro.txt $(DISTRIB_DIR)/gw/setup/
|
||||||
|
mkdir $(DISTRIB_DIR)/gw/setup/lang
|
||||||
|
cp bin/setup/setup.gwf $(DISTRIB_DIR)/gw/setup/
|
||||||
|
cp bin/setup/setup.css $(DISTRIB_DIR)/gw/setup/
|
||||||
|
cp bin/setup/lang/*.htm $(DISTRIB_DIR)/gw/setup/lang/
|
||||||
|
cp bin/setup/lang/lexicon.txt $(DISTRIB_DIR)/gw/setup/lang/
|
||||||
|
cp bin/setup/lang/intro.txt $(DISTRIB_DIR)/gw/setup/lang/
|
||||||
|
@printf "\n\033[1;37m└ Copy plugins in $(DISTRIB_DIR)/gw/plugins\033[0m\n"
|
||||||
|
mkdir $(DISTRIB_DIR)/gw/plugins
|
||||||
|
for P in $(shell ls plugins); do \
|
||||||
|
if [ -f $(BUILD_DIR)/plugins/$$P/plugin_$$P.cmxs ] ; then \
|
||||||
|
mkdir $(DISTRIB_DIR)/gw/plugins/$$P; \
|
||||||
|
cp $(BUILD_DIR)/plugins/$$P/plugin_$$P.cmxs $(DISTRIB_DIR)/gw/plugins/$$P/; \
|
||||||
|
if [ -d plugins/$$P/assets ] ; then \
|
||||||
|
cp -R $(BUILD_DIR)/plugins/$$P/assets $(DISTRIB_DIR)/gw/plugins/$$P/; \
|
||||||
|
fi; \
|
||||||
|
if [ -f $(BUILD_DIR)/plugins/$$P/META ] ; then \
|
||||||
|
cp $(BUILD_DIR)/plugins/$$P/META $(DISTRIB_DIR)/gw/plugins/$$P/; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
@printf "\033[1;37mBuild complete.\033[0m\n"
|
||||||
|
@printf "You can launch Geneweb with “\033[1;37mcd $(DISTRIB_DIR)\033[0m” followed by “\033[1;37mgw/gwd$(EXT)\033[0m”.\n"
|
||||||
|
.PHONY: install uninstall distrib
|
||||||
|
|
||||||
|
# [END] Installation / Distribution section
|
||||||
|
|
||||||
|
doc: ## Documentation generation
|
||||||
|
doc: | $(GENERATED_FILES_DEP)
|
||||||
|
dune build @doc
|
||||||
|
.PHONY: doc
|
||||||
|
|
||||||
|
opendoc: doc
|
||||||
|
xdg-open $(ODOC_DIR)/index.html
|
||||||
|
.PHONY: opendoc
|
||||||
|
|
||||||
|
test: ## Run tests
|
||||||
|
test: | $(GENERATED_FILES_DEP)
|
||||||
|
dune build @runtest
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
|
bench: ## Run benchmarks
|
||||||
|
bench: | $(GENERATED_FILES_DEP)
|
||||||
|
dune build @runbench
|
||||||
|
.PHONY: bench
|
||||||
|
|
||||||
|
BENCH_FILE?=geneweb-bench.bin
|
||||||
|
|
||||||
|
bench-marshal: ## Run benchmarks and record the result
|
||||||
|
bench-marshal: | $(GENERATED_FILES_DEP)
|
||||||
|
ifdef BENCH_NAME
|
||||||
|
dune exec benchmark/bench.exe -- --marshal --name ${BENCH_NAME} ${BENCH_FILE}
|
||||||
|
else
|
||||||
|
$(error BENCH_NAME variable is empty)
|
||||||
|
endif
|
||||||
|
.PHONY: bench-marshal
|
||||||
|
|
||||||
|
bench-tabulate: ## Read BENCH_FILE and print a report
|
||||||
|
bench-tabulate: | $(GENERATED_FILES_DEP)
|
||||||
|
dune exec benchmark/bench.exe -- --tabulate ${BENCH_FILE}
|
||||||
|
@$(RM) $(BENCH_FILE)
|
||||||
|
.PHONY: bench-tabulate
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo -n "Cleaning…"
|
||||||
|
@$(RM) $(GENERATED_FILES_DEP)
|
||||||
|
@$(RM) -r $(DISTRIB_DIR)
|
||||||
|
@dune clean
|
||||||
|
@echo " Done."
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
ci: ## Run tests, skip known failures
|
||||||
|
ci:
|
||||||
|
@ocaml ./configure.ml && $(MAKE) -s clean build && GENEWEB_CI=on dune runtest
|
||||||
|
.PHONY: ci
|
||||||
|
|
||||||
|
ocp-indent: ## Run ocp-indent (inplace edition)
|
||||||
|
ocp-indent:
|
||||||
|
for f in `find lib bin -type f -regex .*[.]ml[i]?` ; do \
|
||||||
|
echo $$f ; \
|
||||||
|
ocp-indent -i $$f ; \
|
||||||
|
done
|
||||||
|
.PHONY: ocp-indent
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
help:
|
||||||
|
@clear;grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' Makefile | awk 'BEGIN {FS = ":.*?#\
|
||||||
|
# "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m## /[33m/'
|
||||||
|
.PHONY: help
|
140
README.md
Normal file
140
README.md
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
# GeneWeb
|
||||||
|
|
||||||
|
[](https://github.com/geneweb/geneweb/actions/workflows/ci.yml)
|
||||||
|
|
||||||
|
GeneWeb is an open source genealogy software written in OCaml. It comes
|
||||||
|
with a Web interface and can be used off-line or as a Web service.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- Documentation maintained by the community: https://geneweb.tuxfamily.org/
|
||||||
|
- GeneWeb API (generated from source): http://geneweb.github.io/geneweb/
|
||||||
|
- GeneWeb overview (realized by OCamlPro): https://geneweb.github.io/
|
||||||
|
|
||||||
|
## Quick and easy live GeneWeb test
|
||||||
|
|
||||||
|
- Test your GeneWeb database on current master: https://github.com/geneweb/geneweb/blob/master/geneweb_colab.ipynb
|
||||||
|
|
||||||
|
## Installation (for users)
|
||||||
|
|
||||||
|
WARNING: before installing a new version of GeneWeb, it is highly recommended to save
|
||||||
|
your bases into .gw formatted files.
|
||||||
|
|
||||||
|
When installing a version of GeneWeb with the "pre-release" qualifier, you are
|
||||||
|
participating to the collective test effort (thanks for your contribution). You should keep aside the previous version
|
||||||
|
you were using and refrain from extensive updates or additions in your bases
|
||||||
|
until the "release" qualifier is effective.
|
||||||
|
|
||||||
|
Any problem you encounter or issue you want to raise should be entered on the issue page
|
||||||
|
of the GitHub repository (https://github.com/geneweb/geneweb/issues).
|
||||||
|
|
||||||
|
Download the file corresponding to your environment from
|
||||||
|
the [releases page](https://github.com/geneweb/geneweb/releases).
|
||||||
|
|
||||||
|
Extract the distribution folder and place it at the location of your choice. You may also rename it.
|
||||||
|
Its content is as follows (this example is for a GNU/Linux distribution;
|
||||||
|
other distributions are very similar):
|
||||||
|
|
||||||
|
```
|
||||||
|
distribution/
|
||||||
|
├── bases
|
||||||
|
├── CHANGES.txt
|
||||||
|
├── gw
|
||||||
|
├── a.gwf
|
||||||
|
├── connex
|
||||||
|
├── consang
|
||||||
|
├── etc
|
||||||
|
├── ged2gwb
|
||||||
|
├── gwb2ged
|
||||||
|
├── gwc
|
||||||
|
├── gwd
|
||||||
|
├── gwd.arg
|
||||||
|
├── gwdiff
|
||||||
|
├── gwfixbase
|
||||||
|
├── gwrepl
|
||||||
|
├── gwsetup
|
||||||
|
├── gwu
|
||||||
|
├── images
|
||||||
|
├── lang
|
||||||
|
├── plugins
|
||||||
|
├── setup
|
||||||
|
└── update_nldb
|
||||||
|
├── gwd.sh
|
||||||
|
├── gwsetup.sh
|
||||||
|
├── install-cgi
|
||||||
|
├── install-cgi.sh
|
||||||
|
├── LICENSE.txt
|
||||||
|
├── LISEZMOI.txt
|
||||||
|
├── README.txt
|
||||||
|
└── START.htm
|
||||||
|
```
|
||||||
|
|
||||||
|
Starting the GeneWeb servers may depend on your specific environment.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### MacOS
|
||||||
|
|
||||||
|
Apple provides a security mechanism preventing users from executing applications
|
||||||
|
which are not provided by authenticated developers. Such applications cannot be started
|
||||||
|
by double-clicking on their icons.
|
||||||
|
Apple provides a two-step mechanism circumventing this security:
|
||||||
|
* Right-click on the application icon (```gwd``` and ```gwsetup```). This will pop-up a window
|
||||||
|
mentioning the security issue and providing an "open" button. Click on this button to open
|
||||||
|
the application. Ignore the resulting messages as no parameters were provided.
|
||||||
|
* Once ```gwd``` and ```gwsetup``` have been started in this fashion, they will be white-listed
|
||||||
|
on your machine and subsequent opens will succeed.
|
||||||
|
|
||||||
|
After white-listing ```gwd``` and ```gwsetup```, double-click on the ```geneweb.command```
|
||||||
|
file which will launch both servers with appropriate parameters.
|
||||||
|
With the configuration provided in this launch command, the bases are located in
|
||||||
|
the ```bases``` folder.
|
||||||
|
You may reorganize your folder structure (and launch command) as described in the
|
||||||
|
documentation at https://geneweb.tuxfamily.org/.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
Quite similar to the MacOS solution, without the security check.
|
||||||
|
```xxx.command``` files have an equivalent ```xxx.sh``` variant.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
* Documentation: https://geneweb.tuxfamily.org/wiki/GeneWeb
|
||||||
|
* Mailing list: https://framalistes.org/sympa/subscribe/geneweb
|
||||||
|
* IRC: irc://irc.libera.chat/geneweb
|
||||||
|
* Git: https://github.com/geneweb/geneweb
|
||||||
|
* Forum: https://www.geneanet.org/forum/GeneWeb-85
|
||||||
|
* Wikipedia: https://en.wikipedia.org/wiki/GeneWeb
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
See [Contributor guidelines](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
### Installation (for developers)
|
||||||
|
|
||||||
|
See [geneweb.opam](./geneweb.opam).
|
||||||
|
|
||||||
|
### Build instructions
|
||||||
|
|
||||||
|
1. Run the configuration script
|
||||||
|
```
|
||||||
|
$ ocaml ./configure.ml
|
||||||
|
```
|
||||||
|
2. Build the distribution
|
||||||
|
```
|
||||||
|
$ make clean distrib
|
||||||
|
```
|
||||||
|
|
||||||
|
You can have a description of available configuration options using
|
||||||
|
```
|
||||||
|
$ ocaml ./configure.ml --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
All files marked in this distribution are Copyright (c) 1998-2016 INRIA
|
||||||
|
(Institut National de Recherche en Informatique et Automatique) and
|
||||||
|
distributed under the GNU GENERAL PUBLIC LICENSE. See [LICENSE](LICENSE) file
|
||||||
|
for details.
|
239
benchmark/bench.ml
Normal file
239
benchmark/bench.ml
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
open Geneweb
|
||||||
|
|
||||||
|
let style = ref Benchmark.Auto
|
||||||
|
|
||||||
|
let test_fn =
|
||||||
|
try
|
||||||
|
let l = String.split_on_char ',' @@ Sys.getenv "BENCH_FN" in
|
||||||
|
fun s -> List.mem s l
|
||||||
|
with Not_found -> fun _ -> true
|
||||||
|
|
||||||
|
let bench ?(t = 1) name fn arg =
|
||||||
|
if test_fn name then (
|
||||||
|
Gc.compact ();
|
||||||
|
Benchmark.throughput1 ~style:!style ~name t (List.map fn) arg)
|
||||||
|
else []
|
||||||
|
|
||||||
|
let list =
|
||||||
|
[
|
||||||
|
1; 2; 10; 100; 1000; 10000; 100000; 1000000; 10000000; 100000000; 1000000000;
|
||||||
|
]
|
||||||
|
|
||||||
|
let sosa_list = List.map Sosa.of_int list
|
||||||
|
|
||||||
|
let bench () =
|
||||||
|
let suite =
|
||||||
|
[
|
||||||
|
bench "Sosa.gen" (List.map Sosa.gen) [ sosa_list ];
|
||||||
|
bench "Sosa.to_string_sep"
|
||||||
|
(List.map @@ Sosa.to_string_sep ",")
|
||||||
|
[ sosa_list ];
|
||||||
|
bench "Sosa.to_string" (List.map Sosa.to_string) [ sosa_list ];
|
||||||
|
bench "Sosa.of_string" (List.map Sosa.of_string)
|
||||||
|
[ List.map string_of_int list ];
|
||||||
|
bench "Sosa.branches" (List.map Sosa.branches) [ sosa_list ];
|
||||||
|
bench "Place.normalize" Geneweb.Place.normalize
|
||||||
|
[
|
||||||
|
"[foo-bar] - boobar (baz)";
|
||||||
|
"[foo-bar] – boobar (baz)";
|
||||||
|
"[foo-bar] — boobar (baz)";
|
||||||
|
];
|
||||||
|
bench "Mutil.unsafe_tr"
|
||||||
|
(fun s -> Mutil.unsafe_tr 'a' 'b' @@ "a" ^ s)
|
||||||
|
[ "aaaaaaaaaa"; "bbbbbbbbbb"; "abbbbbbbb"; "bbbbbbbbba"; "ababababab" ];
|
||||||
|
bench "Mutil.tr"
|
||||||
|
(fun s -> Mutil.tr 'a' 'b' @@ "a" ^ s)
|
||||||
|
[ "aaaaaaaaaa"; "bbbbbbbbbb"; "abbbbbbbb"; "bbbbbbbbba"; "ababababab" ];
|
||||||
|
bench "Mutil.contains"
|
||||||
|
(Mutil.contains "foobarbaz")
|
||||||
|
[ "foo"; "bar"; "baz"; "foobarbaz!" ];
|
||||||
|
bench "Mutil.start_with"
|
||||||
|
(Mutil.start_with "foobarbaz" 0)
|
||||||
|
[ "foo"; "bar"; ""; "foobarbaz" ];
|
||||||
|
bench "Mutil.start_with_wildcard"
|
||||||
|
(Mutil.start_with_wildcard "foobarbaz" 0)
|
||||||
|
[ "foo"; "bar"; ""; "foobarbaz" ];
|
||||||
|
bench "Place.compare_places"
|
||||||
|
(Place.compare_places "[foo-bar] - baz, boobar")
|
||||||
|
[
|
||||||
|
"[foo-bar] - baz, boobar";
|
||||||
|
"[foo-bar] - baz, boobar, barboo";
|
||||||
|
"baz, boobar";
|
||||||
|
];
|
||||||
|
bench "Util.name_with_roman_number" Util.name_with_roman_number
|
||||||
|
[
|
||||||
|
"39 39";
|
||||||
|
"39 x 39";
|
||||||
|
"foo 246";
|
||||||
|
"bar 421 baz";
|
||||||
|
"bar 160 baz 207";
|
||||||
|
"foo bar baz";
|
||||||
|
];
|
||||||
|
bench "Name.lower" Name.lower
|
||||||
|
[ "étienne"; "Étienne"; "ÿvette"; "Ÿvette"; "Ĕtienne" ];
|
||||||
|
bench "Name.split_fname" Name.split_fname
|
||||||
|
[ "Jean-Baptiste Emmanuel"; "Jean Baptiste Emmanuel" ];
|
||||||
|
bench "Name.split_sname" Name.split_sname
|
||||||
|
[ "Jean-Baptiste Emmanuel"; "Jean Baptiste Emmanuel" ];
|
||||||
|
bench ~t:2 "Calendar"
|
||||||
|
(fun () ->
|
||||||
|
let febLength year : int =
|
||||||
|
if (if year < 0 then year + 1 else year) mod 4 = 0 then 29 else 28
|
||||||
|
in
|
||||||
|
let monthLength =
|
||||||
|
[| 31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31 |]
|
||||||
|
in
|
||||||
|
for year = -4713 to 10000 do
|
||||||
|
if year <> 0 then
|
||||||
|
for month = 1 to 12 do
|
||||||
|
let len =
|
||||||
|
if month = 2 then febLength year
|
||||||
|
else Array.get monthLength @@ (month - 1)
|
||||||
|
in
|
||||||
|
for day = 1 to len do
|
||||||
|
let d =
|
||||||
|
{ Def.day; month; year; delta = 0; prec = Def.Sure }
|
||||||
|
in
|
||||||
|
(Sys.opaque_identity ignore)
|
||||||
|
(Calendar.julian_of_sdn Def.Sure @@ Calendar.sdn_of_julian d)
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done)
|
||||||
|
[ () ];
|
||||||
|
]
|
||||||
|
in
|
||||||
|
match Sys.getenv_opt "BENCH_BASE" with
|
||||||
|
| Some bname when bname <> "" ->
|
||||||
|
let conf = Config.empty in
|
||||||
|
let bench_w_base ?t ?(load = []) name fn args =
|
||||||
|
Secure.set_base_dir (Filename.dirname bname);
|
||||||
|
let base = Gwdb.open_base bname in
|
||||||
|
List.iter (fun load -> load base) load;
|
||||||
|
let r = bench ?t name (fn base) args in
|
||||||
|
Gwdb.close_base base;
|
||||||
|
r
|
||||||
|
in
|
||||||
|
bench_w_base "UpdateData.get_all_data"
|
||||||
|
(fun base conf -> UpdateData.get_all_data conf base)
|
||||||
|
[ { conf with Config.env = [ ("data", Adef.encoded "place") ] } ]
|
||||||
|
:: bench_w_base "UpdateData.build_list"
|
||||||
|
(fun base conf -> UpdateData.build_list conf base)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
conf with
|
||||||
|
Config.env = [ ("data", Adef.encoded "src") ];
|
||||||
|
wizard = true;
|
||||||
|
};
|
||||||
|
{
|
||||||
|
conf with
|
||||||
|
Config.env = [ ("data", Adef.encoded "place") ];
|
||||||
|
wizard = true;
|
||||||
|
};
|
||||||
|
]
|
||||||
|
:: bench_w_base "UpdateData.build_list_short"
|
||||||
|
(fun base conf ->
|
||||||
|
UpdateData.build_list_short conf @@ UpdateData.build_list conf base)
|
||||||
|
[
|
||||||
|
{
|
||||||
|
conf with
|
||||||
|
Config.env = [ ("data", Adef.encoded "src") ];
|
||||||
|
wizard = true;
|
||||||
|
};
|
||||||
|
{
|
||||||
|
conf with
|
||||||
|
Config.env = [ ("data", Adef.encoded "place") ];
|
||||||
|
wizard = true;
|
||||||
|
};
|
||||||
|
]
|
||||||
|
:: bench_w_base
|
||||||
|
~load:[ Gwdb.load_persons_array ]
|
||||||
|
"Util.authorized_age"
|
||||||
|
(fun base conf ->
|
||||||
|
Gwdb.Collection.iter
|
||||||
|
(Sys.opaque_identity (fun p ->
|
||||||
|
Sys.opaque_identity ignore
|
||||||
|
@@ Util.authorized_age conf base p))
|
||||||
|
(Gwdb.persons base))
|
||||||
|
[
|
||||||
|
{ conf with wizard = true };
|
||||||
|
{ conf with wizard = false; friend = false };
|
||||||
|
]
|
||||||
|
:: bench_w_base "Check.check_base" ~t:10
|
||||||
|
(fun base _conf ->
|
||||||
|
Check.check_base base
|
||||||
|
(Sys.opaque_identity ignore)
|
||||||
|
(Sys.opaque_identity ignore)
|
||||||
|
(Sys.opaque_identity ignore))
|
||||||
|
[ conf ]
|
||||||
|
:: bench_w_base "Perso.first_possible_duplication" ~t:10
|
||||||
|
(fun base _conf ->
|
||||||
|
Gwdb.Collection.fold
|
||||||
|
(fun acc p ->
|
||||||
|
Perso.first_possible_duplication base (Gwdb.get_iper p) ([], [])
|
||||||
|
:: acc)
|
||||||
|
[] (Gwdb.persons base))
|
||||||
|
[ conf ]
|
||||||
|
:: bench_w_base "BirthDeath.select_person" ~t:10
|
||||||
|
(fun base get ->
|
||||||
|
(Sys.opaque_identity BirthDeath.select_person) conf base get true
|
||||||
|
|> Sys.opaque_identity ignore)
|
||||||
|
[ (fun p -> Date.od_of_cdate (Gwdb.get_birth p)) ]
|
||||||
|
:: suite
|
||||||
|
| _ -> suite
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let marshal = ref false in
|
||||||
|
let tabulate = ref false in
|
||||||
|
let file = ref "" in
|
||||||
|
let name = ref "" in
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
("--marshal", Arg.Set marshal, "");
|
||||||
|
("--tabulate", Arg.Set tabulate, "");
|
||||||
|
("--name", Arg.Set_string name, "");
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let usage = "Usage: " ^ Sys.argv.(0) ^ " [OPTION] [FILES]" in
|
||||||
|
let anonfun s = file := s in
|
||||||
|
Arg.parse speclist anonfun usage;
|
||||||
|
if !marshal then style := Benchmark.Nil;
|
||||||
|
if
|
||||||
|
(!file <> "" && (not !tabulate) && not !marshal)
|
||||||
|
|| (!tabulate && !marshal)
|
||||||
|
|| (!marshal && !name = "")
|
||||||
|
then (
|
||||||
|
Arg.usage speclist usage;
|
||||||
|
exit 2);
|
||||||
|
if !marshal then (
|
||||||
|
let samples : Benchmark.samples list = bench () in
|
||||||
|
let ht =
|
||||||
|
if Sys.file_exists !file then (
|
||||||
|
let ch = open_in_bin !file in
|
||||||
|
let ht : (string, Benchmark.samples) Hashtbl.t =
|
||||||
|
Marshal.from_channel ch
|
||||||
|
in
|
||||||
|
close_in ch;
|
||||||
|
ht)
|
||||||
|
else Hashtbl.create 256
|
||||||
|
in
|
||||||
|
let add k v =
|
||||||
|
match Hashtbl.find_opt ht k with
|
||||||
|
| Some v' -> Hashtbl.replace ht k (v :: v')
|
||||||
|
| None -> Hashtbl.add ht k [ v ]
|
||||||
|
in
|
||||||
|
List.iter
|
||||||
|
(function [ (fn, t) ] -> add fn (!name, t) | _ -> assert false)
|
||||||
|
samples;
|
||||||
|
let ch = open_out_bin !file in
|
||||||
|
Marshal.to_channel ch ht [];
|
||||||
|
close_out ch)
|
||||||
|
else if !tabulate then (
|
||||||
|
let ch = open_in_bin !file in
|
||||||
|
let ht : (string, Benchmark.samples) Hashtbl.t = Marshal.from_channel ch in
|
||||||
|
close_in ch;
|
||||||
|
Hashtbl.iter
|
||||||
|
(fun name samples ->
|
||||||
|
Printf.printf "\n%s:\n" name;
|
||||||
|
Benchmark.tabulate samples)
|
||||||
|
ht)
|
||||||
|
else ignore @@ bench ()
|
10
benchmark/dune.in
Normal file
10
benchmark/dune.in
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
(executable
|
||||||
|
(name bench)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% -V OCAML:%{ocaml_version} %{input-file})))
|
||||||
|
(libraries unix %%%SOSA_PKG%%% %%%GWDB_PKG%%% geneweb benchmark)
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(action (run ./bench.exe) )
|
||||||
|
(alias runbench)
|
||||||
|
)
|
203
bin/cache_files/cache_files.ml
Normal file
203
bin/cache_files/cache_files.ml
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
open Geneweb
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
let bname = ref ""
|
||||||
|
let trace = ref false
|
||||||
|
let fnames = ref false
|
||||||
|
let places = ref false
|
||||||
|
let fname_alias = ref false
|
||||||
|
let snames = ref false
|
||||||
|
let alias = ref false
|
||||||
|
let qual = ref false
|
||||||
|
let all = ref false
|
||||||
|
let prog = ref false
|
||||||
|
|
||||||
|
let write_cache_file bname fname list =
|
||||||
|
let bname =
|
||||||
|
if Filename.check_suffix bname ".gwb" then Filename.remove_extension bname
|
||||||
|
else bname
|
||||||
|
in
|
||||||
|
let fname =
|
||||||
|
Filename.concat
|
||||||
|
(Util.base_path [] (bname ^ ".gwb"))
|
||||||
|
(bname ^ "_" ^ fname ^ "_cache.txt")
|
||||||
|
in
|
||||||
|
Printf.printf "Write to : %s\n" fname;
|
||||||
|
match try Some (Secure.open_out fname) with Sys_error _ -> None with
|
||||||
|
| Some oc ->
|
||||||
|
List.iter (fun (v, _) -> output_string oc ("<option>" ^ v ^ "\n")) list;
|
||||||
|
close_out oc
|
||||||
|
| None -> ()
|
||||||
|
|
||||||
|
let places_all base bname fname =
|
||||||
|
let start = Unix.gettimeofday () in
|
||||||
|
let ht_size = 2048 in
|
||||||
|
(* FIXME: find the good heuristic *)
|
||||||
|
let ht : ('a, 'b) Hashtbl.t = Hashtbl.create ht_size in
|
||||||
|
let ht_add istr _p =
|
||||||
|
let key : 'a = sou base istr in
|
||||||
|
match Hashtbl.find_opt ht key with
|
||||||
|
| Some _ -> Hashtbl.replace ht key key
|
||||||
|
| None -> Hashtbl.add ht key key
|
||||||
|
in
|
||||||
|
let len = nb_of_persons base in
|
||||||
|
if !prog then (
|
||||||
|
Printf.printf "Places\n";
|
||||||
|
flush stdout;
|
||||||
|
ProgrBar.full := '*';
|
||||||
|
ProgrBar.start ());
|
||||||
|
let aux b fn p =
|
||||||
|
if b then
|
||||||
|
let x = fn p in
|
||||||
|
if not (is_empty_string x) then ht_add x p
|
||||||
|
in
|
||||||
|
|
||||||
|
Collection.iteri
|
||||||
|
(fun i ip ->
|
||||||
|
let p = poi base ip in
|
||||||
|
aux true get_birth_place p;
|
||||||
|
aux true get_baptism_place p;
|
||||||
|
aux true get_death_place p;
|
||||||
|
aux true get_burial_place p;
|
||||||
|
if !prog then ProgrBar.run i len else ())
|
||||||
|
(Gwdb.ipers base);
|
||||||
|
|
||||||
|
if !prog then ProgrBar.finish ();
|
||||||
|
let len = nb_of_families base in
|
||||||
|
if !prog then (
|
||||||
|
ProgrBar.full := '*';
|
||||||
|
ProgrBar.start ());
|
||||||
|
|
||||||
|
Collection.iteri
|
||||||
|
(fun i ifam ->
|
||||||
|
let fam = foi base ifam in
|
||||||
|
let pl_ma = get_marriage_place fam in
|
||||||
|
if not (is_empty_string pl_ma) then (
|
||||||
|
let fath = poi base (get_father fam) in
|
||||||
|
let moth = poi base (get_mother fam) in
|
||||||
|
ht_add pl_ma fath;
|
||||||
|
ht_add pl_ma moth);
|
||||||
|
if !prog then ProgrBar.run i len else ())
|
||||||
|
(Gwdb.ifams base);
|
||||||
|
|
||||||
|
if !prog then ProgrBar.finish ();
|
||||||
|
flush stderr;
|
||||||
|
let places_list = Hashtbl.fold (fun _k v acc -> (v, 1) :: acc) ht [] in
|
||||||
|
let places_list =
|
||||||
|
List.sort (fun (v1, _) (v2, _) -> Gutil.alphabetic_utf_8 v1 v2) places_list
|
||||||
|
in
|
||||||
|
write_cache_file bname fname places_list;
|
||||||
|
flush stderr;
|
||||||
|
let stop = Unix.gettimeofday () in
|
||||||
|
Printf.printf "Number of places: %d\n" (List.length places_list);
|
||||||
|
Printf.printf "Execution time: %fs\n" (stop -. start);
|
||||||
|
flush stderr
|
||||||
|
|
||||||
|
let names_all base bname fname =
|
||||||
|
let fn = fname = "fnames" in
|
||||||
|
let sn = fname = "snames" in
|
||||||
|
let start = Unix.gettimeofday () in
|
||||||
|
let ht = Hashtbl.create 1 in
|
||||||
|
let nb_ind = nb_of_persons base in
|
||||||
|
flush stderr;
|
||||||
|
if !prog then (
|
||||||
|
Printf.printf "%s\n" fname;
|
||||||
|
flush stdout;
|
||||||
|
ProgrBar.full := '*';
|
||||||
|
ProgrBar.start ());
|
||||||
|
|
||||||
|
Collection.iteri
|
||||||
|
(fun i ip ->
|
||||||
|
if !prog then ProgrBar.run i nb_ind;
|
||||||
|
let p = poi base ip in
|
||||||
|
let nam =
|
||||||
|
if fn then sou base (get_first_name p)
|
||||||
|
else if sn then sou base (get_surname p)
|
||||||
|
else ""
|
||||||
|
in
|
||||||
|
let al = if !alias then get_aliases p else [] in
|
||||||
|
let qual = if !qual then get_qualifiers p else [] in
|
||||||
|
let fna = if !fname_alias && fn then get_first_names_aliases p else [] in
|
||||||
|
let key = nam in
|
||||||
|
if nam <> "" then
|
||||||
|
if not (Hashtbl.mem ht key) then Hashtbl.add ht key (nam, 1)
|
||||||
|
else
|
||||||
|
let vv, i = Hashtbl.find ht key in
|
||||||
|
Hashtbl.replace ht key (vv, i + 1)
|
||||||
|
else ();
|
||||||
|
let nam2 =
|
||||||
|
if al <> [] then al
|
||||||
|
else if fna <> [] then fna
|
||||||
|
else if qual <> [] then qual
|
||||||
|
else []
|
||||||
|
in
|
||||||
|
if nam2 <> [] then
|
||||||
|
List.iter
|
||||||
|
(fun nam ->
|
||||||
|
let nam = sou base nam in
|
||||||
|
let key = nam in
|
||||||
|
if not (Hashtbl.mem ht key) then Hashtbl.add ht key (nam, 1)
|
||||||
|
else
|
||||||
|
let vv, i = Hashtbl.find ht key in
|
||||||
|
Hashtbl.replace ht key (vv, i + 1))
|
||||||
|
nam2;
|
||||||
|
if !prog then ProgrBar.run i nb_ind else ())
|
||||||
|
(Gwdb.ipers base);
|
||||||
|
|
||||||
|
if !prog then ProgrBar.finish ();
|
||||||
|
flush stderr;
|
||||||
|
let name_list = Hashtbl.fold (fun _k v acc -> v :: acc) ht [] in
|
||||||
|
let name_list = List.sort (fun v1 v2 -> compare v1 v2) name_list in
|
||||||
|
write_cache_file bname fname name_list;
|
||||||
|
flush stderr;
|
||||||
|
let stop = Unix.gettimeofday () in
|
||||||
|
Printf.printf "Number of %s : %d\n" fname (Hashtbl.length ht);
|
||||||
|
Printf.printf "Execution time: %fs\n" (stop -. start);
|
||||||
|
flush stderr
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
("-fn", Arg.Set fnames, "produce first names");
|
||||||
|
("-sn", Arg.Set snames, "produce surnames");
|
||||||
|
("-al", Arg.Set alias, "produce aliases");
|
||||||
|
("-qu", Arg.Set qual, "produce qualifiers");
|
||||||
|
("-pl", Arg.Set places, "produce places");
|
||||||
|
("-all", Arg.Set all, "produce all");
|
||||||
|
("-fna", Arg.Set fname_alias, "add first names aliases");
|
||||||
|
("-prog", Arg.Set prog, "show progress bar");
|
||||||
|
]
|
||||||
|
|
||||||
|
let anonfun i = bname := i
|
||||||
|
|
||||||
|
let usage =
|
||||||
|
"Usage: cache_files [-fn] [-sn] [-al] [-qu] [-pl] [-all] [-fna] [-prog] base\n\
|
||||||
|
\ cd bases; before running cache_files."
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
Arg.parse speclist anonfun usage;
|
||||||
|
if !bname = "" || !bname <> Filename.basename !bname then (
|
||||||
|
Arg.usage speclist usage;
|
||||||
|
exit 2);
|
||||||
|
let base = Gwdb.open_base !bname in
|
||||||
|
bname := Filename.basename !bname;
|
||||||
|
if !places then places_all base !bname "places";
|
||||||
|
if !fnames then names_all base !bname "fnames";
|
||||||
|
if !snames then names_all base !bname "snames";
|
||||||
|
if !alias then names_all base !bname "aliases";
|
||||||
|
if !qual then names_all base !bname "qualifiers";
|
||||||
|
if !all then (
|
||||||
|
places_all base !bname "places";
|
||||||
|
fnames := true;
|
||||||
|
names_all base !bname "fnames";
|
||||||
|
fnames := false;
|
||||||
|
snames := true;
|
||||||
|
names_all base !bname "snames";
|
||||||
|
snames := false;
|
||||||
|
alias := true;
|
||||||
|
names_all base !bname "aliases";
|
||||||
|
alias := false;
|
||||||
|
qual := true;
|
||||||
|
names_all base !bname "qualifiers";
|
||||||
|
qual := false)
|
||||||
|
|
||||||
|
let _ = main ()
|
6
bin/cache_files/dune.in
Normal file
6
bin/cache_files/dune.in
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(executables
|
||||||
|
(names cache_files)
|
||||||
|
(public_names geneweb.cache_files)
|
||||||
|
(modules cache_files)
|
||||||
|
(libraries unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
275
bin/connex/connex.ml
Normal file
275
bin/connex/connex.ml
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
(* Copyright (c) 1999 INRIA *)
|
||||||
|
|
||||||
|
open Def
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
let all = ref false
|
||||||
|
let statistics = ref false
|
||||||
|
let detail = ref 0
|
||||||
|
let ignore = ref []
|
||||||
|
let output = ref ""
|
||||||
|
let ignore_files = ref true
|
||||||
|
let ask_for_delete = ref 0
|
||||||
|
let cnt_for_delete = ref 0
|
||||||
|
let exact = ref false
|
||||||
|
let gwd_port = ref 2317
|
||||||
|
let server = ref "127.0.0.1"
|
||||||
|
|
||||||
|
let rec merge_families ifaml1f ifaml2f =
|
||||||
|
match (ifaml1f, ifaml2f) with
|
||||||
|
| ifam1 :: ifaml1, ifam2 :: ifaml2 ->
|
||||||
|
let m1 = List.memq ifam1 ifaml2 in
|
||||||
|
let m2 = List.memq ifam2 ifaml1 in
|
||||||
|
if m1 && m2 then merge_families ifaml1 ifaml2
|
||||||
|
else if m1 then ifam2 :: merge_families ifaml1f ifaml2
|
||||||
|
else if m2 then ifam1 :: merge_families ifaml1 ifaml2f
|
||||||
|
else if ifam1 == ifam2 then ifam1 :: merge_families ifaml1 ifaml2
|
||||||
|
else ifam1 :: ifam2 :: merge_families ifaml1 ifaml2
|
||||||
|
| ifaml1, [] -> ifaml1
|
||||||
|
| [], ifaml2 -> ifaml2
|
||||||
|
|
||||||
|
let rec filter f = function
|
||||||
|
| x :: l -> if f x then x :: filter f l else filter f l
|
||||||
|
| [] -> []
|
||||||
|
|
||||||
|
let connected_families base ifam cpl =
|
||||||
|
let rec loop ifaml ipl_scanned = function
|
||||||
|
| ip :: ipl ->
|
||||||
|
if List.memq ip ipl_scanned then loop ifaml ipl_scanned ipl
|
||||||
|
else
|
||||||
|
let u = poi base ip in
|
||||||
|
let ifaml1 = Array.to_list (get_family u) in
|
||||||
|
let ifaml = merge_families ifaml ifaml1 in
|
||||||
|
let ipl =
|
||||||
|
List.fold_right
|
||||||
|
(fun ifam ipl ->
|
||||||
|
let cpl = foi base ifam in
|
||||||
|
get_father cpl :: get_mother cpl :: ipl)
|
||||||
|
ifaml1 ipl
|
||||||
|
in
|
||||||
|
loop ifaml (ip :: ipl_scanned) ipl
|
||||||
|
| [] -> ifaml
|
||||||
|
in
|
||||||
|
loop [ ifam ] [] [ get_father cpl ]
|
||||||
|
|
||||||
|
let neighbourgs base ifam =
|
||||||
|
let fam = foi base ifam in
|
||||||
|
let ifaml = connected_families base ifam fam in
|
||||||
|
let ifaml =
|
||||||
|
match get_parents (poi base (get_father fam)) with
|
||||||
|
| Some ifam -> ifam :: ifaml
|
||||||
|
| None -> ifaml
|
||||||
|
in
|
||||||
|
let ifaml =
|
||||||
|
match get_parents (poi base (get_mother fam)) with
|
||||||
|
| Some ifam -> ifam :: ifaml
|
||||||
|
| None -> ifaml
|
||||||
|
in
|
||||||
|
List.fold_left
|
||||||
|
(fun ifaml ip ->
|
||||||
|
let u = poi base ip in
|
||||||
|
List.fold_left
|
||||||
|
(fun ifaml ifam -> ifam :: ifaml)
|
||||||
|
ifaml
|
||||||
|
(Array.to_list (get_family u)))
|
||||||
|
ifaml
|
||||||
|
(Array.to_list (get_children fam))
|
||||||
|
|
||||||
|
let utf8_designation base p =
|
||||||
|
let first_name = p_first_name base p in
|
||||||
|
let surname = p_surname base p in
|
||||||
|
let s = first_name ^ "." ^ string_of_int (get_occ p) ^ " " ^ surname in
|
||||||
|
if first_name = "?" || surname = "?" then
|
||||||
|
s ^ " (i=" ^ string_of_iper (get_iper p) ^ ")"
|
||||||
|
else s
|
||||||
|
|
||||||
|
let wiki_designation base basename p =
|
||||||
|
let first_name = p_first_name base p in
|
||||||
|
let surname = p_surname base p in
|
||||||
|
let s =
|
||||||
|
"[[" ^ first_name ^ "/" ^ surname ^ "/"
|
||||||
|
^ string_of_int (get_occ p)
|
||||||
|
^ "/" ^ first_name ^ "."
|
||||||
|
^ string_of_int (get_occ p)
|
||||||
|
^ " " ^ surname ^ "]]"
|
||||||
|
in
|
||||||
|
if first_name = "?" || surname = "?" then
|
||||||
|
let indx = string_of_iper (get_iper p) in
|
||||||
|
s ^ " <a href=\"http://" ^ !server ^ ":" ^ string_of_int !gwd_port ^ "/"
|
||||||
|
^ basename ^ "?i=" ^ indx ^ "\">(i=" ^ indx ^ ")</a><br>"
|
||||||
|
else s ^ "<br>"
|
||||||
|
|
||||||
|
let print_family base basename ifam =
|
||||||
|
let fam = foi base ifam in
|
||||||
|
let p = poi base (get_father fam) in
|
||||||
|
if !output <> "" then (
|
||||||
|
if sou base (get_first_name p) = "?" || sou base (get_surname p) = "?" then
|
||||||
|
Printf.eprintf "i=%s" (string_of_iper (get_iper p))
|
||||||
|
else Printf.eprintf " - %s" (utf8_designation base p);
|
||||||
|
Printf.eprintf "\n";
|
||||||
|
Printf.eprintf " - %s\n"
|
||||||
|
(utf8_designation base (poi base (get_mother fam)));
|
||||||
|
flush stderr);
|
||||||
|
if sou base (get_first_name p) = "?" || sou base (get_surname p) = "?" then
|
||||||
|
let indx = string_of_iper (get_iper p) in
|
||||||
|
Printf.printf " - <a href=\"http://%s:%d/%s?i=%s\">i=%s</a><br>" !server
|
||||||
|
!gwd_port basename indx indx
|
||||||
|
else Printf.printf " - %s" (wiki_designation base basename p);
|
||||||
|
Printf.printf "\n";
|
||||||
|
Printf.printf " - %s\n"
|
||||||
|
(wiki_designation base basename (poi base (get_mother fam)))
|
||||||
|
|
||||||
|
let kill_family base ip =
|
||||||
|
let u = { family = Array.of_list [] } in
|
||||||
|
patch_union base ip u
|
||||||
|
|
||||||
|
let kill_parents base ip =
|
||||||
|
let a = { parents = None; consang = Adef.fix (-1) } in
|
||||||
|
patch_ascend base ip a
|
||||||
|
|
||||||
|
let effective_del base (ifam, fam) =
|
||||||
|
kill_family base (get_father fam);
|
||||||
|
kill_family base (get_mother fam);
|
||||||
|
Array.iter (kill_parents base) (get_children fam);
|
||||||
|
Gwdb.delete_family base ifam
|
||||||
|
|
||||||
|
let move base basename =
|
||||||
|
load_ascends_array base;
|
||||||
|
load_unions_array base;
|
||||||
|
load_couples_array base;
|
||||||
|
load_descends_array base;
|
||||||
|
Printf.printf "<h3>Connected components of base %s</h3><br>\n" basename;
|
||||||
|
let ic = Unix.open_process_in "date" in
|
||||||
|
let date = input_line ic in
|
||||||
|
let () = close_in ic in
|
||||||
|
Printf.printf "Computed on %s<br><br>\n" date;
|
||||||
|
flush stderr;
|
||||||
|
let mark = Gwdb.ifam_marker (Gwdb.ifams base) false in
|
||||||
|
let min = ref max_int in
|
||||||
|
let max = ref 0 in
|
||||||
|
let hts = Hashtbl.create 100 in
|
||||||
|
Gwdb.Collection.iter
|
||||||
|
(fun ifam ->
|
||||||
|
let fam = foi base ifam in
|
||||||
|
let origin_file = get_origin_file fam in
|
||||||
|
if List.mem (sou base origin_file) !ignore then ()
|
||||||
|
else
|
||||||
|
let nb, ifaml =
|
||||||
|
let rec loop nb rfaml = function
|
||||||
|
| [] -> (nb, rfaml)
|
||||||
|
| ifam :: ifaml ->
|
||||||
|
let j = ifam in
|
||||||
|
if
|
||||||
|
(not (Gwdb.Marker.get mark j))
|
||||||
|
&& (!ignore_files || eq_istr (get_origin_file fam) origin_file)
|
||||||
|
then (
|
||||||
|
Gwdb.Marker.set mark j true;
|
||||||
|
let nl = neighbourgs base ifam in
|
||||||
|
let rfaml =
|
||||||
|
if nb > !detail then
|
||||||
|
if !ask_for_delete > 0 && nb <= !ask_for_delete then
|
||||||
|
ifam :: rfaml
|
||||||
|
else []
|
||||||
|
else ifam :: rfaml
|
||||||
|
in
|
||||||
|
loop (nb + 1) rfaml (List.rev_append nl ifaml))
|
||||||
|
else loop nb rfaml ifaml
|
||||||
|
in
|
||||||
|
loop 0 [] [ ifam ]
|
||||||
|
in
|
||||||
|
if nb > 0 && (!all || nb <= !min) then (
|
||||||
|
if nb <= !min then min := nb;
|
||||||
|
if nb >= !max then max := nb;
|
||||||
|
if !output <> "" then (
|
||||||
|
Printf.eprintf "Connex component \"%s\" length %d\n"
|
||||||
|
(sou base origin_file) nb;
|
||||||
|
flush stderr);
|
||||||
|
Printf.printf "Connex component \"%s\" length %d<br>\n"
|
||||||
|
(sou base origin_file) nb;
|
||||||
|
if !detail == nb then List.iter (print_family base basename) ifaml
|
||||||
|
else print_family base basename ifam;
|
||||||
|
if !statistics then
|
||||||
|
match Hashtbl.find_opt hts nb with
|
||||||
|
| None -> Hashtbl.add hts nb 1
|
||||||
|
| Some n ->
|
||||||
|
Hashtbl.replace hts nb (n + 1);
|
||||||
|
flush stdout;
|
||||||
|
let check_ask =
|
||||||
|
if !exact then nb = !ask_for_delete else nb <= !ask_for_delete
|
||||||
|
in
|
||||||
|
if !ask_for_delete > 0 && check_ask then (
|
||||||
|
(* if -o file, repeat branch definition to stderr! *)
|
||||||
|
Printf.eprintf "Delete up to %d branches of size %s %d ?\n"
|
||||||
|
!cnt_for_delete
|
||||||
|
(if !exact then "=" else "<=")
|
||||||
|
!ask_for_delete;
|
||||||
|
flush stderr;
|
||||||
|
let r =
|
||||||
|
if !cnt_for_delete > 0 then "y"
|
||||||
|
else (
|
||||||
|
Printf.eprintf "Delete that branch (y/N) ?";
|
||||||
|
flush stderr;
|
||||||
|
input_line stdin)
|
||||||
|
in
|
||||||
|
if r = "y" then (
|
||||||
|
decr cnt_for_delete;
|
||||||
|
List.iter
|
||||||
|
(fun ifam ->
|
||||||
|
let fam = foi base ifam in
|
||||||
|
effective_del base (ifam, fam))
|
||||||
|
ifaml;
|
||||||
|
Printf.eprintf "%d families deleted\n" (List.length ifaml);
|
||||||
|
flush stderr)
|
||||||
|
else (
|
||||||
|
Printf.printf "Nothing done.\n";
|
||||||
|
flush stdout))))
|
||||||
|
(Gwdb.ifams base);
|
||||||
|
if !ask_for_delete > 0 then Gwdb.commit_patches base;
|
||||||
|
if !statistics then (
|
||||||
|
Printf.printf "<br>\nStatistics:<br>\n";
|
||||||
|
let ls = Hashtbl.fold (fun nb n ls -> (nb, n) :: ls) hts [] in
|
||||||
|
let ls = List.sort compare ls in
|
||||||
|
let ls = List.rev ls in
|
||||||
|
List.iter (fun (nb, n) -> Printf.printf "%d(%d) " nb n) ls;
|
||||||
|
Printf.printf "\n")
|
||||||
|
|
||||||
|
let bname = ref ""
|
||||||
|
let usage = "usage: " ^ Sys.argv.(0) ^ " <base>"
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
( "-gwd_p",
|
||||||
|
Arg.Int (fun x -> gwd_port := x),
|
||||||
|
"<number>: Specify the port number of gwd (default = "
|
||||||
|
^ string_of_int !gwd_port ^ "); > 1024 for normal users." );
|
||||||
|
( "-server",
|
||||||
|
Arg.String (fun x -> server := x),
|
||||||
|
"<string>: Name of the server (default is 127.0.0.1)." );
|
||||||
|
("-a", Arg.Set all, ": all connex components");
|
||||||
|
("-s", Arg.Set statistics, ": produce statistics");
|
||||||
|
("-d", Arg.Int (fun x -> detail := x), "<int> : detail for this length");
|
||||||
|
( "-i",
|
||||||
|
Arg.String (fun x -> ignore := x :: !ignore),
|
||||||
|
"<file> : ignore this file" );
|
||||||
|
("-bf", Arg.Clear ignore_files, ": by origin files");
|
||||||
|
( "-del",
|
||||||
|
Arg.Int (fun i -> ask_for_delete := i),
|
||||||
|
"<int> : ask for deleting branches whose size <= that value" );
|
||||||
|
( "-cnt",
|
||||||
|
Arg.Int (fun i -> cnt_for_delete := i),
|
||||||
|
"<int> : delete cnt branches whose size <= -del value" );
|
||||||
|
( "-exact",
|
||||||
|
Arg.Set exact,
|
||||||
|
": delete only branches whose size strictly = -del value" );
|
||||||
|
("-o", Arg.String (fun x -> output := x), "<file> : output to this file");
|
||||||
|
]
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
Arg.parse speclist (fun s -> bname := s) usage;
|
||||||
|
if !ask_for_delete > 0 then
|
||||||
|
Lock.control (Mutil.lock_file !bname) false
|
||||||
|
(fun () -> move (Gwdb.open_base !bname) !bname)
|
||||||
|
~onerror:Lock.print_try_again
|
||||||
|
else move (Gwdb.open_base !bname) !bname
|
||||||
|
|
||||||
|
let _ = main ()
|
6
bin/connex/dune.in
Normal file
6
bin/connex/dune.in
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(executables
|
||||||
|
(names connex)
|
||||||
|
(public_names geneweb.connex)
|
||||||
|
(modules connex)
|
||||||
|
(libraries unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
55
bin/consang/consang.ml
Normal file
55
bin/consang/consang.ml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
let fname = ref ""
|
||||||
|
let scratch = ref false
|
||||||
|
let verbosity = ref 2
|
||||||
|
let fast = ref false
|
||||||
|
let errmsg = "usage: " ^ Sys.argv.(0) ^ " [options] <file_name>"
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
("-q", Arg.Unit (fun () -> verbosity := 1), " quiet mode");
|
||||||
|
("-qq", Arg.Unit (fun () -> verbosity := 0), " very quiet mode");
|
||||||
|
("-fast", Arg.Set fast, " faster, but use more memory");
|
||||||
|
("-scratch", Arg.Set scratch, ": from scratch");
|
||||||
|
( "-mem",
|
||||||
|
Arg.Set Outbase.save_mem,
|
||||||
|
": Save memory, but slower when rewritting database" );
|
||||||
|
("-nolock", Arg.Set Lock.no_lock_flag, ": do not lock database.");
|
||||||
|
]
|
||||||
|
|
||||||
|
let anonfun s =
|
||||||
|
if !fname = "" then fname := s
|
||||||
|
else raise (Arg.Bad "Cannot treat several databases")
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
Arg.parse speclist anonfun errmsg;
|
||||||
|
if !fname = "" then (
|
||||||
|
Printf.eprintf "Missing file name\n";
|
||||||
|
Printf.eprintf "Use option -help for usage\n";
|
||||||
|
flush stderr;
|
||||||
|
exit 2);
|
||||||
|
if !verbosity = 0 then Mutil.verbose := false;
|
||||||
|
Secure.set_base_dir (Filename.dirname !fname);
|
||||||
|
Lock.control_retry (Mutil.lock_file !fname) ~onerror:Lock.print_error_and_exit
|
||||||
|
(fun () ->
|
||||||
|
let base = Gwdb.open_base !fname in
|
||||||
|
if !fast then (
|
||||||
|
Gwdb.load_persons_array base;
|
||||||
|
Gwdb.load_families_array base;
|
||||||
|
Gwdb.load_ascends_array base;
|
||||||
|
Gwdb.load_unions_array base;
|
||||||
|
Gwdb.load_couples_array base;
|
||||||
|
Gwdb.load_descends_array base;
|
||||||
|
Gwdb.load_strings_array base);
|
||||||
|
try
|
||||||
|
Sys.catch_break true;
|
||||||
|
if ConsangAll.compute ~verbosity:!verbosity base !scratch then
|
||||||
|
Gwdb.sync base
|
||||||
|
with Consang.TopologicalSortError p ->
|
||||||
|
Printf.printf "\nError: loop in database, %s is his/her own ancestor.\n"
|
||||||
|
(Gutil.designation base p);
|
||||||
|
flush stdout;
|
||||||
|
exit 2)
|
||||||
|
|
||||||
|
let _ = Printexc.print main ()
|
7
bin/consang/dune.in
Normal file
7
bin/consang/dune.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
(executable
|
||||||
|
(name consang)
|
||||||
|
(public_name geneweb.consang)
|
||||||
|
(modules consang)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(libraries unix %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
6
bin/fixbase/dune.in
Normal file
6
bin/fixbase/dune.in
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(executable
|
||||||
|
(name gwfixbase)
|
||||||
|
(public_name geneweb.gwfixbase)
|
||||||
|
(modules gwfixbase)
|
||||||
|
(libraries unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
225
bin/fixbase/gwfixbase.ml
Normal file
225
bin/fixbase/gwfixbase.ml
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
open Geneweb
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
let aux txt
|
||||||
|
(fn :
|
||||||
|
?report:(Fixbase.patch -> unit) -> (int -> int -> unit) -> base -> unit)
|
||||||
|
~v1 ~v2 base n cnt =
|
||||||
|
let string_of_patch =
|
||||||
|
let string_of_p i = Gutil.designation base (poi base i) in
|
||||||
|
let string_of_f i =
|
||||||
|
let fam = foi base i in
|
||||||
|
Printf.sprintf "[%s & %s]"
|
||||||
|
(string_of_p @@ get_father fam)
|
||||||
|
(string_of_p @@ get_mother fam)
|
||||||
|
in
|
||||||
|
function
|
||||||
|
| Fixbase.Fix_NBDS ip ->
|
||||||
|
Printf.sprintf "Fixed pevents for: %s" (string_of_p ip)
|
||||||
|
| Fix_AddedUnion ip -> Printf.sprintf "Added union for: %s" (string_of_p ip)
|
||||||
|
| Fix_AddedParents ip ->
|
||||||
|
Printf.sprintf "Fixed missing parents for: %s" (string_of_p ip)
|
||||||
|
| Fix_ParentDeleted ip ->
|
||||||
|
Printf.sprintf "Deleted parents for: %s" (string_of_p ip)
|
||||||
|
| Fix_AddedChild ifam ->
|
||||||
|
Printf.sprintf "Added child in: %s" (string_of_f ifam)
|
||||||
|
| Fix_RemovedUnion (ip, ifam) ->
|
||||||
|
Printf.sprintf "Removing ifam %s from [%s] unions" (string_of_ifam ifam)
|
||||||
|
(string_of_p ip)
|
||||||
|
| Fix_RemovedDuplicateUnion (ip, ifam) ->
|
||||||
|
Printf.sprintf "Removing duplicate ifam %s from [%s] unions"
|
||||||
|
(string_of_ifam ifam) (string_of_p ip)
|
||||||
|
| Fix_AddedRelatedFromPevent (ip, ip2) | Fix_AddedRelatedFromFevent (ip, ip2)
|
||||||
|
->
|
||||||
|
Printf.sprintf "Added related %s to %s" (string_of_p ip2)
|
||||||
|
(string_of_p ip)
|
||||||
|
| Fix_MarriageDivorce ifam ->
|
||||||
|
Printf.sprintf "Fixed marriage and/or divorce info of %s"
|
||||||
|
(string_of_f ifam)
|
||||||
|
| Fix_MissingSpouse (ifam, iper) ->
|
||||||
|
Printf.sprintf "Fixed missing spouse (%s) in family %s"
|
||||||
|
(string_of_p iper) (string_of_f ifam)
|
||||||
|
| Fix_WrongUTF8Encoding (ifam_opt, iper_opt, opt) ->
|
||||||
|
Printf.sprintf "Fixed invalid UTF-8 sequence (%s): %s"
|
||||||
|
(match ifam_opt with
|
||||||
|
| Some i -> "ifam " ^ string_of_ifam i
|
||||||
|
| None -> (
|
||||||
|
match iper_opt with
|
||||||
|
| Some i -> "iper " ^ string_of_iper i
|
||||||
|
| None -> assert false))
|
||||||
|
(match opt with
|
||||||
|
| Some (i, i') -> string_of_istr i ^ " -> " ^ string_of_istr i'
|
||||||
|
| None -> "Dtext")
|
||||||
|
| Fix_UpdatedOcc (iper, oocc, nocc) ->
|
||||||
|
Printf.sprintf "Uptated occ for %s: %d -> %d" (string_of_p iper) oocc
|
||||||
|
nocc
|
||||||
|
in
|
||||||
|
let i' = ref 0 in
|
||||||
|
if v1 then (
|
||||||
|
print_endline txt;
|
||||||
|
flush stdout;
|
||||||
|
ProgrBar.start ());
|
||||||
|
let progress =
|
||||||
|
if v2 then (fun i n ->
|
||||||
|
ProgrBar.run i n;
|
||||||
|
i' := i)
|
||||||
|
else if v1 then ProgrBar.run
|
||||||
|
else fun _ _ -> ()
|
||||||
|
in
|
||||||
|
let report =
|
||||||
|
if v2 then
|
||||||
|
Some
|
||||||
|
(fun s ->
|
||||||
|
incr cnt;
|
||||||
|
ProgrBar.suspend ();
|
||||||
|
print_endline @@ "\t" ^ string_of_patch s;
|
||||||
|
flush stdout;
|
||||||
|
ProgrBar.restart !i' n)
|
||||||
|
else Some (fun _ -> incr cnt)
|
||||||
|
in
|
||||||
|
fn ?report progress base;
|
||||||
|
if v1 then ProgrBar.finish ()
|
||||||
|
|
||||||
|
let check_NBDS = aux "Check persons' NBDS" Fixbase.check_NBDS
|
||||||
|
|
||||||
|
let check_families_parents =
|
||||||
|
aux "Check families' parents" Fixbase.check_families_parents
|
||||||
|
|
||||||
|
let check_families_children =
|
||||||
|
aux "Check families' children" Fixbase.check_families_children
|
||||||
|
|
||||||
|
let check_persons_parents =
|
||||||
|
aux "Check persons' parents" Fixbase.check_persons_parents
|
||||||
|
|
||||||
|
let check_persons_families =
|
||||||
|
aux "Check persons' families" Fixbase.check_persons_families
|
||||||
|
|
||||||
|
let check_pevents_witnesses =
|
||||||
|
aux "Check persons' events witnesses" Fixbase.check_pevents_witnesses
|
||||||
|
|
||||||
|
let check_fevents_witnesses =
|
||||||
|
aux "Check family events witnesses" Fixbase.check_fevents_witnesses
|
||||||
|
|
||||||
|
let fix_marriage_divorce =
|
||||||
|
aux "Fix families' marriage and divorce" Fixbase.fix_marriage_divorce
|
||||||
|
|
||||||
|
let fix_utf8_sequence =
|
||||||
|
aux "Fix invalid UTF-8 sequence" Fixbase.fix_utf8_sequence
|
||||||
|
|
||||||
|
let fix_key = aux "Fix duplicate keys" Fixbase.fix_key
|
||||||
|
|
||||||
|
let check ~dry_run ~verbosity ~fast ~f_parents ~f_children ~p_parents
|
||||||
|
~p_families ~p_NBDS ~pevents_witnesses ~fevents_witnesses ~marriage_divorce
|
||||||
|
~invalid_utf8 ~key bname =
|
||||||
|
let v1 = !verbosity >= 1 in
|
||||||
|
let v2 = !verbosity >= 2 in
|
||||||
|
if not v1 then Mutil.verbose := false;
|
||||||
|
let fast = !fast in
|
||||||
|
let base = Gwdb.open_base bname in
|
||||||
|
let fix = ref 0 in
|
||||||
|
let nb_fam = nb_of_families base in
|
||||||
|
let nb_ind = nb_of_persons base in
|
||||||
|
if fast then (
|
||||||
|
load_strings_array base;
|
||||||
|
load_persons_array base);
|
||||||
|
if !f_parents then check_families_parents ~v1 ~v2 base nb_fam fix;
|
||||||
|
if !f_children then check_families_children ~v1 ~v2 base nb_fam fix;
|
||||||
|
if !p_parents then check_persons_parents ~v1 ~v2 base nb_ind fix;
|
||||||
|
if !p_NBDS then check_NBDS base ~v1 ~v2 nb_ind fix;
|
||||||
|
if !p_families then check_persons_families ~v1 ~v2 base nb_ind fix;
|
||||||
|
if !pevents_witnesses then check_pevents_witnesses ~v1 ~v2 base nb_ind fix;
|
||||||
|
if !fevents_witnesses then check_fevents_witnesses ~v1 ~v2 base nb_fam fix;
|
||||||
|
if !marriage_divorce then fix_marriage_divorce ~v1 ~v2 base nb_fam fix;
|
||||||
|
if !invalid_utf8 then fix_utf8_sequence ~v1 ~v2 base nb_fam fix;
|
||||||
|
if !key then fix_key ~v1 ~v2 base nb_ind fix;
|
||||||
|
if fast then (
|
||||||
|
clear_strings_array base;
|
||||||
|
clear_persons_array base);
|
||||||
|
if not !dry_run then (
|
||||||
|
if !fix <> 0 then (
|
||||||
|
Gwdb.commit_patches base;
|
||||||
|
if v1 then (
|
||||||
|
Printf.printf "%n changes commited\n" !fix;
|
||||||
|
flush stdout))
|
||||||
|
else if v1 then (
|
||||||
|
Printf.printf "No change\n";
|
||||||
|
flush stdout);
|
||||||
|
if v1 then (
|
||||||
|
Printf.printf "Rebuilding the indexes..\n";
|
||||||
|
flush stdout);
|
||||||
|
Gwdb.sync base;
|
||||||
|
if v1 then (
|
||||||
|
Printf.printf "Done";
|
||||||
|
flush stdout))
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
let bname = ref ""
|
||||||
|
let verbosity = ref 2
|
||||||
|
let fast = ref false
|
||||||
|
let f_parents = ref false
|
||||||
|
let f_children = ref false
|
||||||
|
let p_parents = ref false
|
||||||
|
let p_families = ref false
|
||||||
|
let p_NBDS = ref false
|
||||||
|
let pevents_witnesses = ref false
|
||||||
|
let fevents_witnesses = ref false
|
||||||
|
let marriage_divorce = ref false
|
||||||
|
let invalid_utf8 = ref false
|
||||||
|
let key = ref false
|
||||||
|
let index = ref false
|
||||||
|
let dry_run = ref false
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
("-dry-run", Arg.Set dry_run, " do not commit changes (only print)");
|
||||||
|
("-q", Arg.Unit (fun () -> verbosity := 1), " quiet mode");
|
||||||
|
("-qq", Arg.Unit (fun () -> verbosity := 0), " very quiet mode");
|
||||||
|
("-fast", Arg.Set fast, " fast mode. Needs more memory.");
|
||||||
|
("-families-parents", Arg.Set f_parents, " missing doc");
|
||||||
|
("-families-children", Arg.Set f_children, " missing doc");
|
||||||
|
("-persons-NBDS", Arg.Set p_parents, " missing doc");
|
||||||
|
("-persons-parents", Arg.Set p_parents, " missing doc");
|
||||||
|
("-persons-families", Arg.Set p_families, " missing doc");
|
||||||
|
("-pevents-witnesses", Arg.Set pevents_witnesses, " missing doc");
|
||||||
|
("-fevents-witnesses", Arg.Set fevents_witnesses, " missing doc");
|
||||||
|
("-marriage-divorce", Arg.Set marriage_divorce, " missing doc");
|
||||||
|
("-person-key", Arg.Set key, " missing doc");
|
||||||
|
( "-index",
|
||||||
|
Arg.Set index,
|
||||||
|
" rebuild index. It is automatically enable by any other option." );
|
||||||
|
("-invalid-utf8", Arg.Set invalid_utf8, " missing doc");
|
||||||
|
]
|
||||||
|
|
||||||
|
let anonfun i = bname := i
|
||||||
|
let usage = "Usage: " ^ Sys.argv.(0) ^ " [OPTION] base"
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
Arg.parse speclist anonfun usage;
|
||||||
|
Secure.set_base_dir (Filename.dirname !bname);
|
||||||
|
if !bname = "" then (
|
||||||
|
Arg.usage speclist usage;
|
||||||
|
exit 2);
|
||||||
|
Lock.control (Mutil.lock_file !bname) false ~onerror:Lock.print_try_again
|
||||||
|
@@ fun () ->
|
||||||
|
if
|
||||||
|
!f_parents || !f_children || !p_parents || !p_families || !pevents_witnesses
|
||||||
|
|| !fevents_witnesses || !marriage_divorce || !p_NBDS || !invalid_utf8
|
||||||
|
|| !key || !index
|
||||||
|
then ()
|
||||||
|
else (
|
||||||
|
f_parents := true;
|
||||||
|
f_children := true;
|
||||||
|
p_parents := true;
|
||||||
|
p_families := true;
|
||||||
|
pevents_witnesses := true;
|
||||||
|
fevents_witnesses := true;
|
||||||
|
marriage_divorce := true;
|
||||||
|
p_NBDS := true;
|
||||||
|
invalid_utf8 := true;
|
||||||
|
key := true);
|
||||||
|
check ~dry_run ~fast ~verbosity ~f_parents ~f_children ~p_NBDS ~p_parents
|
||||||
|
~p_families ~pevents_witnesses ~fevents_witnesses ~marriage_divorce
|
||||||
|
~invalid_utf8 ~key !bname
|
||||||
|
|
||||||
|
let _ = main ()
|
7
bin/ged2gwb/dune.in
Normal file
7
bin/ged2gwb/dune.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
(executable
|
||||||
|
(name ged2gwb)
|
||||||
|
(public_name geneweb.ged2gwb)
|
||||||
|
(modules ged2gwb)
|
||||||
|
(preprocess (action (run camlp5o pr_o.cmo pa_extend.cmo q_MLast.cmo %{input-file})))
|
||||||
|
(libraries camlp5 unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
3311
bin/ged2gwb/ged2gwb.ml
Normal file
3311
bin/ged2gwb/ged2gwb.ml
Normal file
File diff suppressed because it is too large
Load Diff
22
bin/gwb2ged/dune.in
Normal file
22
bin/gwb2ged/dune.in
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
(library
|
||||||
|
(name gwb2ged_lib)
|
||||||
|
(public_name geneweb.gwb2ged_lib)
|
||||||
|
(wrapped false)
|
||||||
|
(libraries geneweb geneweb.gwexport_lib)
|
||||||
|
(modules gwb2gedLib)
|
||||||
|
)
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name gwb2ged)
|
||||||
|
(public_name geneweb.gwb2ged)
|
||||||
|
(modules gwb2ged)
|
||||||
|
(libraries
|
||||||
|
geneweb
|
||||||
|
gwb2ged_lib
|
||||||
|
gwu_lib
|
||||||
|
str
|
||||||
|
unix
|
||||||
|
%%%GWDB_PKG%%%
|
||||||
|
%%%SOSA_PKG%%%
|
||||||
|
)
|
||||||
|
)
|
15
bin/gwb2ged/gwb2ged.ml
Normal file
15
bin/gwb2ged/gwb2ged.ml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
let with_indexes = ref false
|
||||||
|
|
||||||
|
let speclist opts =
|
||||||
|
("-indexes", Arg.Set with_indexes, " export indexes in gedcom")
|
||||||
|
:: Gwexport.speclist opts
|
||||||
|
|> Arg.align
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
let opts = ref Gwexport.default_opts in
|
||||||
|
Arg.parse (speclist opts) (Gwexport.anonfun opts) Gwexport.errmsg;
|
||||||
|
let opts = !opts in
|
||||||
|
let select = Gwexport.select opts [] in
|
||||||
|
Gwb2gedLib.gwb2ged !with_indexes opts select
|
||||||
|
|
||||||
|
let _ = main ()
|
725
bin/gwb2ged/gwb2gedLib.ml
Normal file
725
bin/gwb2ged/gwb2gedLib.ml
Normal file
@ -0,0 +1,725 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
open Geneweb
|
||||||
|
open Def
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
let int_of_iper =
|
||||||
|
let ht = Hashtbl.create 0 in
|
||||||
|
fun i ->
|
||||||
|
try Hashtbl.find ht i
|
||||||
|
with Not_found ->
|
||||||
|
let x = Hashtbl.length ht in
|
||||||
|
Hashtbl.add ht i x;
|
||||||
|
x
|
||||||
|
|
||||||
|
let int_of_ifam =
|
||||||
|
let ht = Hashtbl.create 0 in
|
||||||
|
fun i ->
|
||||||
|
try Hashtbl.find ht i
|
||||||
|
with Not_found ->
|
||||||
|
let x = Hashtbl.length ht in
|
||||||
|
Hashtbl.add ht i x;
|
||||||
|
x
|
||||||
|
|
||||||
|
let month_txt =
|
||||||
|
[|
|
||||||
|
"JAN";
|
||||||
|
"FEB";
|
||||||
|
"MAR";
|
||||||
|
"APR";
|
||||||
|
"MAY";
|
||||||
|
"JUN";
|
||||||
|
"JUL";
|
||||||
|
"AUG";
|
||||||
|
"SEP";
|
||||||
|
"OCT";
|
||||||
|
"NOV";
|
||||||
|
"DEC";
|
||||||
|
|]
|
||||||
|
|
||||||
|
let french_txt =
|
||||||
|
[|
|
||||||
|
"VEND";
|
||||||
|
"BRUM";
|
||||||
|
"FRIM";
|
||||||
|
"NIVO";
|
||||||
|
"PLUV";
|
||||||
|
"VENT";
|
||||||
|
"GERM";
|
||||||
|
"FLOR";
|
||||||
|
"PRAI";
|
||||||
|
"MESS";
|
||||||
|
"THER";
|
||||||
|
"FRUC";
|
||||||
|
"COMP";
|
||||||
|
|]
|
||||||
|
|
||||||
|
let hebrew_txt =
|
||||||
|
[|
|
||||||
|
"TSH";
|
||||||
|
"CSH";
|
||||||
|
"KSL";
|
||||||
|
"TVT";
|
||||||
|
"SHV";
|
||||||
|
"ADR";
|
||||||
|
"ADS";
|
||||||
|
"NSN";
|
||||||
|
"IYR";
|
||||||
|
"SVN";
|
||||||
|
"TMZ";
|
||||||
|
"AAV";
|
||||||
|
"ELL";
|
||||||
|
|]
|
||||||
|
|
||||||
|
let ged_month cal m =
|
||||||
|
match cal with
|
||||||
|
| Dgregorian | Djulian ->
|
||||||
|
if m >= 1 && m <= Array.length month_txt then month_txt.(m - 1)
|
||||||
|
else failwith "ged_month"
|
||||||
|
| Dfrench ->
|
||||||
|
if m >= 1 && m <= Array.length french_txt then french_txt.(m - 1)
|
||||||
|
else failwith "ged_month"
|
||||||
|
| Dhebrew ->
|
||||||
|
if m >= 1 && m <= Array.length hebrew_txt then hebrew_txt.(m - 1)
|
||||||
|
else failwith "ged_month"
|
||||||
|
|
||||||
|
let encode opts s =
|
||||||
|
match opts.Gwexport.charset with
|
||||||
|
| Gwexport.Ansel -> Ansel.of_iso_8859_1 @@ Mutil.iso_8859_1_of_utf_8 s
|
||||||
|
| Gwexport.Ascii | Gwexport.Ansi -> Mutil.iso_8859_1_of_utf_8 s
|
||||||
|
| Gwexport.Utf8 -> s
|
||||||
|
|
||||||
|
let max_len = 78
|
||||||
|
let br = "<br>"
|
||||||
|
|
||||||
|
let find_br s ini_i =
|
||||||
|
let ini = "<br" in
|
||||||
|
let rec loop i j =
|
||||||
|
if i = String.length ini then
|
||||||
|
let rec loop2 j =
|
||||||
|
if j = String.length s then br
|
||||||
|
else if s.[j] = '>' then String.sub s ini_i (j - ini_i + 1)
|
||||||
|
else loop2 (j + 1)
|
||||||
|
in
|
||||||
|
loop2 j
|
||||||
|
else if j = String.length s then br
|
||||||
|
else if String.unsafe_get ini i = String.unsafe_get s j then
|
||||||
|
loop (i + 1) (j + 1)
|
||||||
|
else br
|
||||||
|
in
|
||||||
|
loop 0 ini_i
|
||||||
|
|
||||||
|
let oc opts = match opts.Gwexport.oc with _, oc, _ -> oc
|
||||||
|
|
||||||
|
(** [display_note_aux opts tagn s len i] outputs text [s] with CONT/CONC
|
||||||
|
tag. GEDCOM lines are limited to 255 characters. However, the
|
||||||
|
CONCatenation or CONTinuation tags can be used to expand a field
|
||||||
|
beyond this limit. Lines are cut and align with [max_len]
|
||||||
|
characters for easy display/printing.
|
||||||
|
@see <https://www.familysearch.org/developers/docs/gedcom/> GEDCOM
|
||||||
|
STANDARD 5.5, Appendix A CONC and CONT tag
|
||||||
|
@param opts carries output channel
|
||||||
|
@param tagn specifies the current gedcom tag level (0, 1, ...)
|
||||||
|
@param s specifies text to print to the output channel (already
|
||||||
|
encode with gedcom charset)
|
||||||
|
@param len specifies the number of characters (char or wide char)
|
||||||
|
already printed
|
||||||
|
@param i specifies the last char index (index to s -- one byte
|
||||||
|
char) *)
|
||||||
|
|
||||||
|
let rec display_note_aux opts tagn s len i =
|
||||||
|
let j = ref i in
|
||||||
|
(* read wide char (case charset UTF-8) or char (other charset) in s string*)
|
||||||
|
if !j = String.length s then Printf.ksprintf (oc opts) "\n"
|
||||||
|
else
|
||||||
|
(* \n, <br>, <br \> : cut text for CONTinuate with new gedcom line *)
|
||||||
|
let br = find_br s i in
|
||||||
|
if
|
||||||
|
i <= String.length s - String.length br
|
||||||
|
&& String.lowercase_ascii (String.sub s i (String.length br)) = br
|
||||||
|
then (
|
||||||
|
Printf.ksprintf (oc opts) "\n%d CONT " (succ tagn);
|
||||||
|
let i = i + String.length br in
|
||||||
|
let i = if i < String.length s && s.[i] = '\n' then i + 1 else i in
|
||||||
|
display_note_aux opts tagn s
|
||||||
|
(String.length (string_of_int (succ tagn) ^ " CONT "))
|
||||||
|
i)
|
||||||
|
else if s.[i] = '\n' then (
|
||||||
|
Printf.ksprintf (oc opts) "\n%d CONT " (succ tagn);
|
||||||
|
let i = if i < String.length s then i + 1 else i in
|
||||||
|
display_note_aux opts tagn s
|
||||||
|
(String.length (string_of_int (succ tagn) ^ " CONT "))
|
||||||
|
i)
|
||||||
|
else if
|
||||||
|
(* cut text at max length for CONCat with next gedcom line *)
|
||||||
|
len = max_len
|
||||||
|
then (
|
||||||
|
Printf.ksprintf (oc opts) "\n%d CONC " (succ tagn);
|
||||||
|
display_note_aux opts tagn s
|
||||||
|
(String.length (string_of_int (succ tagn) ^ " CONC "))
|
||||||
|
i)
|
||||||
|
else
|
||||||
|
(* continue same gedcom line *)
|
||||||
|
|
||||||
|
(* FIXME: Rewrite this so we can get rid of this custom [nbc] *)
|
||||||
|
let nbc c =
|
||||||
|
if Char.code c < 0b10000000 then 1
|
||||||
|
else if Char.code c < 0b11000000 then -1
|
||||||
|
else if Char.code c < 0b11100000 then 2
|
||||||
|
else if Char.code c < 0b11110000 then 3
|
||||||
|
else if Char.code c < 0b11111000 then 4
|
||||||
|
else if Char.code c < 0b11111100 then 5
|
||||||
|
else if Char.code c < 0b11111110 then 6
|
||||||
|
else -1
|
||||||
|
in
|
||||||
|
(* FIXME: avoid this buffer *)
|
||||||
|
let b = Buffer.create 4 in
|
||||||
|
let rec output_onechar () =
|
||||||
|
if !j = String.length s then decr j (* non wide char / UTF-8 char *)
|
||||||
|
else if opts.Gwexport.charset <> Gwexport.Utf8 then
|
||||||
|
Buffer.add_char b s.[i] (* 1 to 4 bytes UTF-8 wide char *)
|
||||||
|
else if i = !j || nbc s.[!j] = -1 then (
|
||||||
|
Buffer.add_char b s.[!j];
|
||||||
|
incr j;
|
||||||
|
output_onechar ())
|
||||||
|
else decr j
|
||||||
|
in
|
||||||
|
output_onechar ();
|
||||||
|
(oc opts) (Buffer.contents b);
|
||||||
|
display_note_aux opts tagn s (len + 1) (!j + 1)
|
||||||
|
|
||||||
|
let display_note opts tagn s =
|
||||||
|
let tag = Printf.sprintf "%d NOTE " tagn in
|
||||||
|
Printf.ksprintf (oc opts) "%s" tag;
|
||||||
|
display_note_aux opts tagn (encode opts s) (String.length tag) 0
|
||||||
|
|
||||||
|
let ged_header opts base ifile ofile =
|
||||||
|
Printf.ksprintf (oc opts) "0 HEAD\n";
|
||||||
|
Printf.ksprintf (oc opts) "1 SOUR GeneWeb\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 VERS %s\n" Version.ver;
|
||||||
|
Printf.ksprintf (oc opts) "2 NAME %s\n" (Filename.basename Sys.argv.(0));
|
||||||
|
Printf.ksprintf (oc opts) "2 CORP INRIA\n";
|
||||||
|
Printf.ksprintf (oc opts) "3 ADDR http://www.geneweb.org\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 DATA %s\n"
|
||||||
|
(let fname = Filename.basename ifile in
|
||||||
|
if Filename.check_suffix fname ".gwb" then fname else fname ^ ".gwb");
|
||||||
|
(try
|
||||||
|
let tm = Unix.localtime (Unix.time ()) in
|
||||||
|
let mon = ged_month Dgregorian (tm.Unix.tm_mon + 1) in
|
||||||
|
Printf.ksprintf (oc opts) "1 DATE %02d %s %d\n" tm.Unix.tm_mday mon
|
||||||
|
(1900 + tm.Unix.tm_year);
|
||||||
|
Printf.ksprintf (oc opts) "2 TIME %02d:%02d:%02d\n" tm.Unix.tm_hour
|
||||||
|
tm.Unix.tm_min tm.Unix.tm_sec
|
||||||
|
with _ -> ());
|
||||||
|
if ofile <> "" then
|
||||||
|
Printf.ksprintf (oc opts) "1 FILE %s\n" (Filename.basename ofile);
|
||||||
|
Printf.ksprintf (oc opts) "1 GEDC\n";
|
||||||
|
(match opts.Gwexport.charset with
|
||||||
|
| Gwexport.Ansel | Gwexport.Ansi | Gwexport.Ascii ->
|
||||||
|
Printf.ksprintf (oc opts) "2 VERS 5.5\n"
|
||||||
|
| Gwexport.Utf8 -> Printf.ksprintf (oc opts) "2 VERS 5.5.1\n");
|
||||||
|
Printf.ksprintf (oc opts) "2 FORM LINEAGE-LINKED\n";
|
||||||
|
(match opts.Gwexport.charset with
|
||||||
|
| Gwexport.Ansel -> Printf.ksprintf (oc opts) "1 CHAR ANSEL\n"
|
||||||
|
| Gwexport.Ansi -> Printf.ksprintf (oc opts) "1 CHAR ANSI\n"
|
||||||
|
| Gwexport.Ascii -> Printf.ksprintf (oc opts) "1 CHAR ASCII\n"
|
||||||
|
| Gwexport.Utf8 -> Printf.ksprintf (oc opts) "1 CHAR UTF-8\n");
|
||||||
|
if opts.Gwexport.no_notes = `none then
|
||||||
|
match base_notes_read base "" with "" -> () | s -> display_note opts 1 s
|
||||||
|
|
||||||
|
let sub_string_index s t =
|
||||||
|
let rec loop i j =
|
||||||
|
if j = String.length t then Some (i - j)
|
||||||
|
else if i = String.length s then None
|
||||||
|
else if s.[i] = t.[j] then loop (i + 1) (j + 1)
|
||||||
|
else loop (i + 1) 0
|
||||||
|
in
|
||||||
|
loop 0 0
|
||||||
|
|
||||||
|
let ged_1st_name base p =
|
||||||
|
let fn = sou base (get_first_name p) in
|
||||||
|
match get_first_names_aliases p with
|
||||||
|
| n :: _ -> (
|
||||||
|
let fna = sou base n in
|
||||||
|
match sub_string_index fna fn with
|
||||||
|
| Some i ->
|
||||||
|
let j = i + String.length fn in
|
||||||
|
String.sub fna 0 i ^ "\"" ^ fn ^ "\""
|
||||||
|
^ String.sub fna j (String.length fna - j)
|
||||||
|
| None -> fn)
|
||||||
|
| [] -> fn
|
||||||
|
|
||||||
|
let string_of_list =
|
||||||
|
let rec loop r = function
|
||||||
|
| s :: l -> if r = "" then loop s l else loop (r ^ "," ^ s) l
|
||||||
|
| [] -> r
|
||||||
|
in
|
||||||
|
loop ""
|
||||||
|
|
||||||
|
let ged_index opts per =
|
||||||
|
Printf.ksprintf (oc opts) "1 _GWID %s\n" (Gwdb.string_of_iper (get_iper per))
|
||||||
|
|
||||||
|
let ged_name opts base per =
|
||||||
|
Printf.ksprintf (oc opts) "1 NAME %s /%s/\n"
|
||||||
|
(encode opts (Mutil.nominative (ged_1st_name base per)))
|
||||||
|
(encode opts (Mutil.nominative (sou base (get_surname per))));
|
||||||
|
let n = sou base (get_public_name per) in
|
||||||
|
if n <> "" then Printf.ksprintf (oc opts) "2 GIVN %s\n" (encode opts n);
|
||||||
|
(match get_qualifiers per with
|
||||||
|
| nn :: _ ->
|
||||||
|
Printf.ksprintf (oc opts) "2 NICK %s\n" (encode opts (sou base nn))
|
||||||
|
| [] -> ());
|
||||||
|
(match get_surnames_aliases per with
|
||||||
|
| [] -> ()
|
||||||
|
| list ->
|
||||||
|
let list = List.map (fun n -> encode opts (sou base n)) list in
|
||||||
|
Printf.ksprintf (oc opts) "2 SURN %s\n" (string_of_list list));
|
||||||
|
List.iter
|
||||||
|
(fun s ->
|
||||||
|
Printf.ksprintf (oc opts) "1 NAME %s\n" (encode opts (sou base s)))
|
||||||
|
(get_aliases per)
|
||||||
|
|
||||||
|
let ged_sex opts per =
|
||||||
|
match get_sex per with
|
||||||
|
| Male -> Printf.ksprintf (oc opts) "1 SEX M\n"
|
||||||
|
| Female -> Printf.ksprintf (oc opts) "1 SEX F\n"
|
||||||
|
| Neuter -> ()
|
||||||
|
|
||||||
|
let ged_calendar opts = function
|
||||||
|
| Dgregorian -> ()
|
||||||
|
| Djulian -> Printf.ksprintf (oc opts) "@#DJULIAN@ "
|
||||||
|
| Dfrench -> Printf.ksprintf (oc opts) "@#DFRENCH R@ "
|
||||||
|
| Dhebrew -> Printf.ksprintf (oc opts) "@#DHEBREW@ "
|
||||||
|
|
||||||
|
let ged_date_dmy opts dt cal =
|
||||||
|
(match dt.prec with
|
||||||
|
| Sure -> ()
|
||||||
|
| About -> Printf.ksprintf (oc opts) "ABT "
|
||||||
|
| Maybe -> Printf.ksprintf (oc opts) "EST "
|
||||||
|
| Before -> Printf.ksprintf (oc opts) "BEF "
|
||||||
|
| After -> Printf.ksprintf (oc opts) "AFT "
|
||||||
|
| OrYear _ -> Printf.ksprintf (oc opts) "BET "
|
||||||
|
| YearInt _ -> Printf.ksprintf (oc opts) "BET ");
|
||||||
|
ged_calendar opts cal;
|
||||||
|
if dt.day <> 0 then Printf.ksprintf (oc opts) "%02d " dt.day;
|
||||||
|
if dt.month <> 0 then Printf.ksprintf (oc opts) "%s " (ged_month cal dt.month);
|
||||||
|
Printf.ksprintf (oc opts) "%d" dt.year;
|
||||||
|
match dt.prec with
|
||||||
|
| OrYear dmy2 ->
|
||||||
|
Printf.ksprintf (oc opts) " AND ";
|
||||||
|
ged_calendar opts cal;
|
||||||
|
if dmy2.day2 <> 0 then Printf.ksprintf (oc opts) "%02d " dmy2.day2;
|
||||||
|
if dmy2.month2 <> 0 then
|
||||||
|
Printf.ksprintf (oc opts) "%s " (ged_month cal dmy2.month2);
|
||||||
|
Printf.ksprintf (oc opts) "%d" dmy2.year2
|
||||||
|
| YearInt dmy2 ->
|
||||||
|
Printf.ksprintf (oc opts) " AND ";
|
||||||
|
ged_calendar opts cal;
|
||||||
|
if dmy2.day2 <> 0 then Printf.ksprintf (oc opts) "%02d " dmy2.day2;
|
||||||
|
if dmy2.month2 <> 0 then
|
||||||
|
Printf.ksprintf (oc opts) "%s " (ged_month cal dmy2.month2);
|
||||||
|
Printf.ksprintf (oc opts) "%d" dmy2.year2
|
||||||
|
| _ -> ()
|
||||||
|
|
||||||
|
let ged_date opts = function
|
||||||
|
| Dgreg (d, Dgregorian) -> ged_date_dmy opts d Dgregorian
|
||||||
|
| Dgreg (d, Djulian) ->
|
||||||
|
ged_date_dmy opts (Calendar.julian_of_gregorian d) Djulian
|
||||||
|
| Dgreg (d, Dfrench) ->
|
||||||
|
ged_date_dmy opts (Calendar.french_of_gregorian d) Dfrench
|
||||||
|
| Dgreg (d, Dhebrew) ->
|
||||||
|
ged_date_dmy opts (Calendar.hebrew_of_gregorian d) Dhebrew
|
||||||
|
| Dtext t -> Printf.ksprintf (oc opts) "(%s)" t
|
||||||
|
|
||||||
|
let print_sour opts n s = Printf.ksprintf (oc opts) "%d SOUR %s\n" n s
|
||||||
|
|
||||||
|
let ged_ev_detail opts n typ d pl note src =
|
||||||
|
(match (typ, d, pl, note, src) with
|
||||||
|
| "", None, "", "", "" -> Printf.ksprintf (oc opts) " Y"
|
||||||
|
| _ -> ());
|
||||||
|
Printf.ksprintf (oc opts) "\n";
|
||||||
|
if typ = "" then () else Printf.ksprintf (oc opts) "%d TYPE %s\n" n typ;
|
||||||
|
(match d with
|
||||||
|
| Some d ->
|
||||||
|
Printf.ksprintf (oc opts) "%d DATE " n;
|
||||||
|
ged_date opts d;
|
||||||
|
Printf.ksprintf (oc opts) "\n"
|
||||||
|
| None -> ());
|
||||||
|
if pl <> "" then Printf.ksprintf (oc opts) "%d PLAC %s\n" n (encode opts pl);
|
||||||
|
if opts.Gwexport.no_notes <> `nnn && note <> "" then display_note opts n note;
|
||||||
|
if opts.Gwexport.source = None && src <> "" then
|
||||||
|
print_sour opts n (encode opts src)
|
||||||
|
|
||||||
|
let ged_tag_pevent base evt =
|
||||||
|
match evt.epers_name with
|
||||||
|
| Epers_Birth -> "BIRT"
|
||||||
|
| Epers_Baptism -> "BAPM"
|
||||||
|
| Epers_Death -> "DEAT"
|
||||||
|
| Epers_Burial -> "BURI"
|
||||||
|
| Epers_Cremation -> "CREM"
|
||||||
|
| Epers_Accomplishment -> "Accomplishment"
|
||||||
|
| Epers_Acquisition -> "Acquisition"
|
||||||
|
| Epers_Adhesion -> "Membership"
|
||||||
|
| Epers_BaptismLDS -> "BAPL"
|
||||||
|
| Epers_BarMitzvah -> "BARM"
|
||||||
|
| Epers_BatMitzvah -> "BASM"
|
||||||
|
| Epers_Benediction -> "BLES"
|
||||||
|
| Epers_ChangeName -> "Change name"
|
||||||
|
| Epers_Circumcision -> "Circumcision"
|
||||||
|
| Epers_Confirmation -> "CONF"
|
||||||
|
| Epers_ConfirmationLDS -> "CONL"
|
||||||
|
| Epers_Decoration -> "Award"
|
||||||
|
| Epers_DemobilisationMilitaire -> "Military discharge"
|
||||||
|
| Epers_Diploma -> "Degree"
|
||||||
|
| Epers_Distinction -> "Distinction"
|
||||||
|
| Epers_Dotation -> "ENDL"
|
||||||
|
| Epers_DotationLDS -> "DotationLDS"
|
||||||
|
| Epers_Education -> "EDUC"
|
||||||
|
| Epers_Election -> "Election"
|
||||||
|
| Epers_Emigration -> "EMIG"
|
||||||
|
| Epers_Excommunication -> "Excommunication"
|
||||||
|
| Epers_FamilyLinkLDS -> "Family link LDS"
|
||||||
|
| Epers_FirstCommunion -> "FCOM"
|
||||||
|
| Epers_Funeral -> "Funeral"
|
||||||
|
| Epers_Graduate -> "GRAD"
|
||||||
|
| Epers_Hospitalisation -> "Hospitalization"
|
||||||
|
| Epers_Illness -> "Illness"
|
||||||
|
| Epers_Immigration -> "IMMI"
|
||||||
|
| Epers_ListePassenger -> "Passenger list"
|
||||||
|
| Epers_MilitaryDistinction -> "Military distinction"
|
||||||
|
| Epers_MilitaryPromotion -> "Military promotion"
|
||||||
|
| Epers_MilitaryService -> "Military service"
|
||||||
|
| Epers_MobilisationMilitaire -> "Military mobilization"
|
||||||
|
| Epers_Naturalisation -> "NATU"
|
||||||
|
| Epers_Occupation -> "OCCU"
|
||||||
|
| Epers_Ordination -> "ORDN"
|
||||||
|
| Epers_Property -> "PROP"
|
||||||
|
| Epers_Recensement -> "CENS"
|
||||||
|
| Epers_Residence -> "RESI"
|
||||||
|
| Epers_Retired -> "RETI"
|
||||||
|
| Epers_ScellentChildLDS -> "SLGC"
|
||||||
|
| Epers_ScellentParentLDS -> "Scellent parent LDS"
|
||||||
|
| Epers_ScellentSpouseLDS -> "SLGS"
|
||||||
|
| Epers_VenteBien -> "Property sale"
|
||||||
|
| Epers_Will -> "WILL"
|
||||||
|
| Epers_Name n -> sou base n
|
||||||
|
|
||||||
|
let is_primary_pevents = function
|
||||||
|
| Epers_Birth | Epers_Baptism | Epers_Death | Epers_Burial | Epers_Cremation
|
||||||
|
| Epers_BaptismLDS | Epers_BarMitzvah | Epers_BatMitzvah | Epers_Benediction
|
||||||
|
| Epers_Confirmation | Epers_ConfirmationLDS | Epers_Dotation
|
||||||
|
| Epers_Education | Epers_Emigration | Epers_FirstCommunion | Epers_Graduate
|
||||||
|
| Epers_Immigration | Epers_Naturalisation | Epers_Occupation
|
||||||
|
| Epers_Ordination | Epers_Property | Epers_Recensement | Epers_Residence
|
||||||
|
| Epers_Retired | Epers_ScellentChildLDS | Epers_ScellentSpouseLDS
|
||||||
|
| Epers_Will ->
|
||||||
|
true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let relation_format_of_witness_kind :
|
||||||
|
witness_kind -> ('a, unit, string, unit) format4 = function
|
||||||
|
| Witness -> "3 RELA Witness"
|
||||||
|
| Witness_GodParent -> "3 RELA GODP"
|
||||||
|
| Witness_CivilOfficer -> "3 RELA Civil officer"
|
||||||
|
| Witness_ReligiousOfficer -> "3 RELA Religious officer"
|
||||||
|
| Witness_Informant -> "3 RELA Informant"
|
||||||
|
| Witness_Attending -> "3 RELA Attending"
|
||||||
|
| Witness_Mentioned -> "3 RELA Mentioned"
|
||||||
|
| Witness_Other -> "3 RELA Other"
|
||||||
|
|
||||||
|
let oc' opts s = Printf.ksprintf (oc opts) (s ^^ "\n")
|
||||||
|
let oc_witness_kind opts wk = oc' opts (relation_format_of_witness_kind wk)
|
||||||
|
|
||||||
|
let ged_pevent opts base per_sel evt =
|
||||||
|
let typ =
|
||||||
|
if is_primary_pevents evt.epers_name then (
|
||||||
|
let tag = ged_tag_pevent base evt in
|
||||||
|
Printf.ksprintf (oc opts) "1 %s" tag;
|
||||||
|
"")
|
||||||
|
else (
|
||||||
|
Printf.ksprintf (oc opts) "1 EVEN";
|
||||||
|
ged_tag_pevent base evt)
|
||||||
|
in
|
||||||
|
let date = Date.od_of_cdate evt.epers_date in
|
||||||
|
let place = sou base evt.epers_place in
|
||||||
|
let note = sou base evt.epers_note in
|
||||||
|
let src = sou base evt.epers_src in
|
||||||
|
ged_ev_detail opts 2 typ date place note src;
|
||||||
|
Array.iter
|
||||||
|
(fun (ip, wk) ->
|
||||||
|
if per_sel ip then (
|
||||||
|
Printf.ksprintf (oc opts) "2 ASSO @I%d@\n" (int_of_iper ip + 1);
|
||||||
|
Printf.ksprintf (oc opts) "3 TYPE INDI\n";
|
||||||
|
oc_witness_kind opts wk))
|
||||||
|
evt.epers_witnesses
|
||||||
|
|
||||||
|
let adop_fam_list = ref []
|
||||||
|
|
||||||
|
let ged_fam_adop opts i (fath, moth, _) =
|
||||||
|
Printf.ksprintf (oc opts) "0 @F%d@ FAM\n" i;
|
||||||
|
(match fath with
|
||||||
|
| Some i -> Printf.ksprintf (oc opts) "1 HUSB @I%d@\n" (int_of_iper i + 1)
|
||||||
|
| _ -> ());
|
||||||
|
match moth with
|
||||||
|
| Some i -> Printf.ksprintf (oc opts) "1 WIFE @I%d@\n" (int_of_iper i + 1)
|
||||||
|
| _ -> ()
|
||||||
|
|
||||||
|
let ged_ind_ev_str opts base per per_sel =
|
||||||
|
List.iter (ged_pevent opts base per_sel) (get_pevents per)
|
||||||
|
|
||||||
|
let ged_title opts base per tit =
|
||||||
|
Printf.ksprintf (oc opts) "1 TITL ";
|
||||||
|
Printf.ksprintf (oc opts) "%s" (encode opts (sou base tit.t_ident));
|
||||||
|
(match sou base tit.t_place with
|
||||||
|
| "" -> ()
|
||||||
|
| pl -> Printf.ksprintf (oc opts) ", %s" (encode opts pl));
|
||||||
|
if tit.t_nth <> 0 then Printf.ksprintf (oc opts) ", %d" tit.t_nth;
|
||||||
|
Printf.ksprintf (oc opts) "\n";
|
||||||
|
(match
|
||||||
|
(Date.od_of_cdate tit.t_date_start, Date.od_of_cdate tit.t_date_end)
|
||||||
|
with
|
||||||
|
| None, None -> ()
|
||||||
|
| Some sd, None ->
|
||||||
|
Printf.ksprintf (oc opts) "2 DATE FROM ";
|
||||||
|
ged_date opts sd;
|
||||||
|
Printf.ksprintf (oc opts) "\n"
|
||||||
|
| None, Some sd ->
|
||||||
|
Printf.ksprintf (oc opts) "2 DATE TO ";
|
||||||
|
ged_date opts sd;
|
||||||
|
Printf.ksprintf (oc opts) "\n"
|
||||||
|
| Some sd1, Some sd2 ->
|
||||||
|
Printf.ksprintf (oc opts) "2 DATE FROM ";
|
||||||
|
ged_date opts sd1;
|
||||||
|
Printf.ksprintf (oc opts) " TO ";
|
||||||
|
ged_date opts sd2;
|
||||||
|
Printf.ksprintf (oc opts) "\n");
|
||||||
|
match tit.t_name with
|
||||||
|
| Tmain ->
|
||||||
|
Printf.ksprintf (oc opts) "2 NOTE %s\n"
|
||||||
|
(encode opts (sou base (get_public_name per)))
|
||||||
|
| Tname n ->
|
||||||
|
Printf.ksprintf (oc opts) "2 NOTE %s\n" (encode opts (sou base n))
|
||||||
|
| Tnone -> ()
|
||||||
|
|
||||||
|
let ged_ind_attr_str opts base per =
|
||||||
|
(match sou base (get_occupation per) with
|
||||||
|
| "" -> ()
|
||||||
|
| occu -> Printf.ksprintf (oc opts) "1 OCCU %s\n" (encode opts occu));
|
||||||
|
List.iter (ged_title opts base per) (get_titles per)
|
||||||
|
|
||||||
|
let ged_famc opts fam_sel asc =
|
||||||
|
match get_parents asc with
|
||||||
|
| Some ifam ->
|
||||||
|
if fam_sel ifam then
|
||||||
|
Printf.ksprintf (oc opts) "1 FAMC @F%d@\n" (int_of_ifam ifam + 1)
|
||||||
|
| None -> ()
|
||||||
|
|
||||||
|
let ged_fams opts fam_sel ifam =
|
||||||
|
if fam_sel ifam then
|
||||||
|
Printf.ksprintf (oc opts) "1 FAMS @F%d@\n" (int_of_ifam ifam + 1)
|
||||||
|
|
||||||
|
let ged_godparent opts per_sel godp = function
|
||||||
|
| Some ip ->
|
||||||
|
if per_sel ip then (
|
||||||
|
Printf.ksprintf (oc opts) "1 ASSO @I%d@\n" (int_of_iper ip + 1);
|
||||||
|
Printf.ksprintf (oc opts) "2 TYPE INDI\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 RELA %s\n" godp)
|
||||||
|
| None -> ()
|
||||||
|
|
||||||
|
let ged_witness opts fam_sel ifam =
|
||||||
|
if fam_sel ifam then (
|
||||||
|
Printf.ksprintf (oc opts) "1 ASSO @F%d@\n" (int_of_ifam ifam + 1);
|
||||||
|
Printf.ksprintf (oc opts) "2 TYPE FAM\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 RELA witness\n")
|
||||||
|
|
||||||
|
let ged_asso opts base (per_sel, fam_sel) per =
|
||||||
|
List.iter
|
||||||
|
(fun r ->
|
||||||
|
if r.r_type = GodParent then (
|
||||||
|
ged_godparent opts per_sel "GODF" r.r_fath;
|
||||||
|
ged_godparent opts per_sel "GODM" r.r_moth))
|
||||||
|
(get_rparents per);
|
||||||
|
List.iter
|
||||||
|
(fun ic ->
|
||||||
|
let c = poi base ic in
|
||||||
|
if get_sex c = Male then
|
||||||
|
List.iter
|
||||||
|
(fun ifam ->
|
||||||
|
let fam = foi base ifam in
|
||||||
|
if Array.mem (get_iper per) (get_witnesses fam) then
|
||||||
|
ged_witness opts fam_sel ifam)
|
||||||
|
(Array.to_list (get_family c)))
|
||||||
|
(get_related per)
|
||||||
|
|
||||||
|
let ged_psource opts base per =
|
||||||
|
match opts.Gwexport.source with
|
||||||
|
| Some "" -> ()
|
||||||
|
| Some s -> print_sour opts 1 (encode opts s)
|
||||||
|
| None -> (
|
||||||
|
match sou base (get_psources per) with
|
||||||
|
| "" -> ()
|
||||||
|
| s -> print_sour opts 1 (encode opts s))
|
||||||
|
|
||||||
|
let has_image_file opts base p =
|
||||||
|
let s = Image.default_portrait_filename base p in
|
||||||
|
let f = Filename.concat opts.Gwexport.img_base_path s in
|
||||||
|
if Sys.file_exists (f ^ ".gif") then Some (f ^ ".gif")
|
||||||
|
else if Sys.file_exists (f ^ ".jpg") then Some (f ^ ".jpg")
|
||||||
|
else if Sys.file_exists (f ^ ".png") then Some (f ^ ".png")
|
||||||
|
else None
|
||||||
|
|
||||||
|
let ged_multimedia_link opts base per =
|
||||||
|
match sou base (get_image per) with
|
||||||
|
| "" -> (
|
||||||
|
if (not opts.Gwexport.no_picture) && opts.Gwexport.picture_path then
|
||||||
|
match has_image_file opts base per with
|
||||||
|
| Some s ->
|
||||||
|
Printf.ksprintf (oc opts) "1 OBJE\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 FILE %s\n" s
|
||||||
|
| None -> ())
|
||||||
|
| s ->
|
||||||
|
if not opts.Gwexport.no_picture then (
|
||||||
|
Printf.ksprintf (oc opts) "1 OBJE\n";
|
||||||
|
Printf.ksprintf (oc opts) "2 FILE %s\n" s)
|
||||||
|
|
||||||
|
let ged_note opts base per =
|
||||||
|
if opts.Gwexport.no_notes <> `nnn then
|
||||||
|
match sou base (get_notes per) with "" -> () | s -> display_note opts 1 s
|
||||||
|
|
||||||
|
let ged_tag_fevent base evt =
|
||||||
|
match evt.efam_name with
|
||||||
|
| Efam_Marriage -> "MARR"
|
||||||
|
| Efam_NoMarriage -> "unmarried"
|
||||||
|
| Efam_NoMention -> "nomen"
|
||||||
|
| Efam_Engage -> "ENGA"
|
||||||
|
| Efam_Divorce -> "DIV"
|
||||||
|
| Efam_Separated -> "SEP"
|
||||||
|
| Efam_Annulation -> "ANUL"
|
||||||
|
| Efam_MarriageBann -> "MARB"
|
||||||
|
| Efam_MarriageContract -> "MARC"
|
||||||
|
| Efam_MarriageLicense -> "MARL"
|
||||||
|
| Efam_PACS -> "pacs"
|
||||||
|
| Efam_Residence -> "residence"
|
||||||
|
| Efam_Name n -> sou base n
|
||||||
|
|
||||||
|
let is_primary_fevents = function
|
||||||
|
| Efam_Marriage | Efam_Engage | Efam_Divorce | Efam_Separated
|
||||||
|
| Efam_Annulation | Efam_MarriageBann | Efam_MarriageContract
|
||||||
|
| Efam_MarriageLicense ->
|
||||||
|
true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let ged_fevent opts base per_sel evt =
|
||||||
|
let typ =
|
||||||
|
if is_primary_fevents evt.efam_name then (
|
||||||
|
let tag = ged_tag_fevent base evt in
|
||||||
|
Printf.ksprintf (oc opts) "1 %s" tag;
|
||||||
|
"")
|
||||||
|
else (
|
||||||
|
Printf.ksprintf (oc opts) "1 EVEN";
|
||||||
|
ged_tag_fevent base evt)
|
||||||
|
in
|
||||||
|
let date = Date.od_of_cdate evt.efam_date in
|
||||||
|
let place = sou base evt.efam_place in
|
||||||
|
let note = sou base evt.efam_note in
|
||||||
|
let src = sou base evt.efam_src in
|
||||||
|
ged_ev_detail opts 2 typ date place note src;
|
||||||
|
Array.iter
|
||||||
|
(fun (ip, wk) ->
|
||||||
|
if per_sel ip then (
|
||||||
|
Printf.ksprintf (oc opts) "2 ASSO @I%d@\n" (int_of_iper ip + 1);
|
||||||
|
Printf.ksprintf (oc opts) "3 TYPE INDI\n";
|
||||||
|
oc_witness_kind opts wk))
|
||||||
|
evt.efam_witnesses
|
||||||
|
|
||||||
|
let ged_child opts per_sel chil =
|
||||||
|
if per_sel chil then
|
||||||
|
Printf.ksprintf (oc opts) "1 CHIL @I%d@\n" (int_of_iper chil + 1)
|
||||||
|
|
||||||
|
let ged_fsource opts base fam =
|
||||||
|
match opts.Gwexport.source with
|
||||||
|
| Some "" -> ()
|
||||||
|
| Some s -> print_sour opts 1 (encode opts s)
|
||||||
|
| None -> (
|
||||||
|
match sou base (get_fsources fam) with
|
||||||
|
| "" -> ()
|
||||||
|
| s -> print_sour opts 1 (encode opts s))
|
||||||
|
|
||||||
|
let ged_comment opts base fam =
|
||||||
|
if opts.Gwexport.no_notes <> `nnn then
|
||||||
|
match sou base (get_comment fam) with
|
||||||
|
| "" -> ()
|
||||||
|
| s -> display_note opts 1 s
|
||||||
|
|
||||||
|
let has_personal_infos base per =
|
||||||
|
get_parents per <> None
|
||||||
|
|| sou base (get_first_name per) <> "?"
|
||||||
|
|| sou base (get_surname per) <> "?"
|
||||||
|
|| get_birth per <> Date.cdate_None
|
||||||
|
|| sou base (get_birth_place per) <> ""
|
||||||
|
|| (get_death per <> NotDead && get_death per <> DontKnowIfDead)
|
||||||
|
|| sou base (get_occupation per) <> ""
|
||||||
|
|| get_titles per <> []
|
||||||
|
|
||||||
|
let ged_ind_record with_indexes opts base ((per_sel, fam_sel) as sel) i =
|
||||||
|
let per = poi base i in
|
||||||
|
if has_personal_infos base per then (
|
||||||
|
Printf.ksprintf (oc opts) "0 @I%d@ INDI\n" (int_of_iper i + 1);
|
||||||
|
ged_name opts base per;
|
||||||
|
if with_indexes then ged_index opts per;
|
||||||
|
ged_sex opts per;
|
||||||
|
ged_ind_ev_str opts base per per_sel;
|
||||||
|
ged_ind_attr_str opts base per;
|
||||||
|
ged_famc opts fam_sel per;
|
||||||
|
Array.iter (ged_fams opts fam_sel) (get_family per);
|
||||||
|
ged_asso opts base sel per;
|
||||||
|
ged_psource opts base per;
|
||||||
|
ged_multimedia_link opts base per;
|
||||||
|
ged_note opts base per)
|
||||||
|
|
||||||
|
let ged_fam_record opts base (per_sel, _fam_sel) ifam =
|
||||||
|
let fam = foi base ifam in
|
||||||
|
Printf.ksprintf (oc opts) "0 @F%d@ FAM\n" (int_of_ifam ifam + 1);
|
||||||
|
List.iter (ged_fevent opts base per_sel) (get_fevents fam);
|
||||||
|
if
|
||||||
|
per_sel (get_father fam)
|
||||||
|
&& has_personal_infos base (poi base (get_father fam))
|
||||||
|
then
|
||||||
|
Printf.ksprintf (oc opts) "1 HUSB @I%d@\n" (int_of_iper (get_father fam) + 1);
|
||||||
|
if
|
||||||
|
per_sel (get_mother fam)
|
||||||
|
&& has_personal_infos base (poi base (get_mother fam))
|
||||||
|
then
|
||||||
|
Printf.ksprintf (oc opts) "1 WIFE @I%d@\n" (int_of_iper (get_mother fam) + 1);
|
||||||
|
Array.iter (ged_child opts per_sel) (get_children fam);
|
||||||
|
ged_fsource opts base fam;
|
||||||
|
ged_comment opts base fam
|
||||||
|
|
||||||
|
let gwb2ged with_indexes opts ((per_sel, fam_sel) as sel) =
|
||||||
|
match opts.Gwexport.base with
|
||||||
|
| Some (ifile, base) ->
|
||||||
|
let ofile, oc, close = opts.Gwexport.oc in
|
||||||
|
if not opts.Gwexport.mem then (
|
||||||
|
load_ascends_array base;
|
||||||
|
load_unions_array base;
|
||||||
|
load_couples_array base;
|
||||||
|
load_descends_array base);
|
||||||
|
ged_header opts base ifile ofile;
|
||||||
|
Gwdb.Collection.iter
|
||||||
|
(fun i -> if per_sel i then ged_ind_record with_indexes opts base sel i)
|
||||||
|
(Gwdb.ipers base);
|
||||||
|
Gwdb.Collection.iter
|
||||||
|
(fun i -> if fam_sel i then ged_fam_record opts base sel i)
|
||||||
|
(Gwdb.ifams base);
|
||||||
|
let _ =
|
||||||
|
List.fold_right
|
||||||
|
(fun adop i ->
|
||||||
|
ged_fam_adop opts i adop;
|
||||||
|
i + 1)
|
||||||
|
!adop_fam_list
|
||||||
|
(nb_of_families base + 1)
|
||||||
|
in
|
||||||
|
Printf.ksprintf oc "0 TRLR\n";
|
||||||
|
close ()
|
||||||
|
| None -> assert false
|
11
bin/gwb2ged/gwb2gedLib.mli
Normal file
11
bin/gwb2ged/gwb2gedLib.mli
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
val gwb2ged :
|
||||||
|
bool ->
|
||||||
|
Gwexport.gwexport_opts ->
|
||||||
|
(Gwdb.iper -> bool) * (Gwdb.ifam -> bool) ->
|
||||||
|
unit
|
||||||
|
(** [gwb2ged with_indexes opts sel]
|
||||||
|
Converts a Geneweb database to a GEDCOM file.
|
||||||
|
* `with_indexes` specifies if indexes are printed or not;
|
||||||
|
* `opts` are the export options
|
||||||
|
* `sel` is a pair of selectors returned by the database export
|
||||||
|
*)
|
1702
bin/gwc/db1link.ml
Normal file
1702
bin/gwc/db1link.ml
Normal file
File diff suppressed because it is too large
Load Diff
27
bin/gwc/db1link.mli
Normal file
27
bin/gwc/db1link.mli
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
val default_source : string ref
|
||||||
|
(** Default source field for persons and families without source data *)
|
||||||
|
|
||||||
|
val do_check : bool ref
|
||||||
|
(** Base consistency check *)
|
||||||
|
|
||||||
|
val do_consang : bool ref
|
||||||
|
(** Compute consanguinity *)
|
||||||
|
|
||||||
|
val pr_stats : bool ref
|
||||||
|
(** Print base's statistics *)
|
||||||
|
|
||||||
|
val particules_file : string ref
|
||||||
|
(** File containing the particles to use *)
|
||||||
|
|
||||||
|
type file_info = {
|
||||||
|
mutable f_curr_src_file : string;
|
||||||
|
mutable f_curr_gwo_file : string;
|
||||||
|
mutable f_separate : bool;
|
||||||
|
mutable f_bnotes : [ `drop | `erase | `first | `merge ];
|
||||||
|
mutable f_shift : int;
|
||||||
|
mutable f_local_names : (int * int, int) Hashtbl.t;
|
||||||
|
}
|
||||||
|
(** Information about current .gwo file. *)
|
||||||
|
|
||||||
|
val link : (file_info -> unit -> Gwcomp.gw_syntax option) -> string -> bool
|
||||||
|
(** Link .gwo files and create a database. *)
|
7
bin/gwc/dune.in
Normal file
7
bin/gwc/dune.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
(executable
|
||||||
|
(name gwc)
|
||||||
|
(public_name geneweb.gwc)
|
||||||
|
(modules gwc gwcomp db1link)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(libraries unix %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
206
bin/gwc/gwc.ml
Normal file
206
bin/gwc/gwc.ml
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
open Gwcomp
|
||||||
|
|
||||||
|
(** Checks a .gwo header and prints fails if header is absent or not compatible. *)
|
||||||
|
let check_magic fname ic =
|
||||||
|
let b = really_input_string ic (String.length magic_gwo) in
|
||||||
|
if b <> magic_gwo then
|
||||||
|
if String.sub magic_gwo 0 4 = String.sub b 0 4 then
|
||||||
|
failwith ("\"" ^ fname ^ "\" is a GeneWeb object file, but not compatible")
|
||||||
|
else
|
||||||
|
failwith
|
||||||
|
("\"" ^ fname
|
||||||
|
^ "\" is not a GeneWeb object file, or it is a very old version")
|
||||||
|
|
||||||
|
(** [next_family_fun_templ gwo_list fi] creates a function that read
|
||||||
|
sucessivly a [Gwcomp.gw_syntax] for all .gwo files. In details it does :
|
||||||
|
|
||||||
|
- Switch to the next element in the [gwo_list] if reached the end
|
||||||
|
of the current file. Each element is [(gwo,separate, bnotes, shift)]
|
||||||
|
where [gwo] is .gwo filename and [separate], [bnotes], [shift] are
|
||||||
|
captured options from command line related to the giving file.
|
||||||
|
- Modify [fi] with mentioned previusly information if needed.
|
||||||
|
- Start/continue to read current .gwo file content and return
|
||||||
|
[Gwcomp.gw_syntax]. [None] is returned when reading of the last
|
||||||
|
.gwo file reaches end of file *)
|
||||||
|
let next_family_fun_templ gwo_list fi =
|
||||||
|
let ngwo = List.length gwo_list in
|
||||||
|
let run =
|
||||||
|
if ngwo < 10 || not !Mutil.verbose then fun () -> ()
|
||||||
|
else if ngwo < 60 then (fun () ->
|
||||||
|
Printf.eprintf ".";
|
||||||
|
flush stderr)
|
||||||
|
else
|
||||||
|
let bar_cnt = ref 0 in
|
||||||
|
let run () =
|
||||||
|
ProgrBar.run !bar_cnt ngwo;
|
||||||
|
incr bar_cnt
|
||||||
|
in
|
||||||
|
ProgrBar.empty := 'o';
|
||||||
|
ProgrBar.full := '*';
|
||||||
|
ProgrBar.start ();
|
||||||
|
run
|
||||||
|
in
|
||||||
|
let ic_opt = ref None in
|
||||||
|
let gwo_list = ref gwo_list in
|
||||||
|
fun () ->
|
||||||
|
let rec loop () =
|
||||||
|
let r =
|
||||||
|
match !ic_opt with
|
||||||
|
| Some ic -> (
|
||||||
|
match
|
||||||
|
try Some (input_value ic : gw_syntax) with End_of_file -> None
|
||||||
|
with
|
||||||
|
| Some fam -> Some fam
|
||||||
|
| None ->
|
||||||
|
close_in ic;
|
||||||
|
ic_opt := None;
|
||||||
|
None)
|
||||||
|
| None -> None
|
||||||
|
in
|
||||||
|
let bnotes_of_string = function
|
||||||
|
| "merge" -> `merge
|
||||||
|
| "erase" -> `erase
|
||||||
|
| "first" -> `first
|
||||||
|
| "drop" -> `drop
|
||||||
|
| _ -> assert false
|
||||||
|
in
|
||||||
|
match r with
|
||||||
|
| Some fam -> Some fam
|
||||||
|
| None -> (
|
||||||
|
(* switch to the next .gwo file *)
|
||||||
|
match !gwo_list with
|
||||||
|
| (x, separate, bnotes, shift) :: rest ->
|
||||||
|
run ();
|
||||||
|
gwo_list := rest;
|
||||||
|
let ic = open_in_bin x in
|
||||||
|
check_magic x ic;
|
||||||
|
fi.Db1link.f_curr_src_file <- input_value ic;
|
||||||
|
fi.Db1link.f_curr_gwo_file <- x;
|
||||||
|
fi.Db1link.f_separate <- separate;
|
||||||
|
fi.Db1link.f_bnotes <- bnotes_of_string bnotes;
|
||||||
|
fi.Db1link.f_shift <- shift;
|
||||||
|
Hashtbl.clear fi.Db1link.f_local_names;
|
||||||
|
ic_opt := Some ic;
|
||||||
|
loop ()
|
||||||
|
| [] ->
|
||||||
|
if ngwo < 10 || not !Mutil.verbose then ()
|
||||||
|
else if ngwo < 60 then (
|
||||||
|
Printf.eprintf "\n";
|
||||||
|
flush stderr)
|
||||||
|
else ProgrBar.finish ();
|
||||||
|
None)
|
||||||
|
in
|
||||||
|
loop ()
|
||||||
|
|
||||||
|
let just_comp = ref false
|
||||||
|
let out_file = ref (Filename.concat Filename.current_dir_name "a")
|
||||||
|
let force = ref false
|
||||||
|
let separate = ref false
|
||||||
|
let bnotes = ref "merge"
|
||||||
|
let shift = ref 0
|
||||||
|
let files = ref []
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
( "-bnotes",
|
||||||
|
Arg.Set_string bnotes,
|
||||||
|
"[drop|erase|first|merge] Behavior for base notes of the next file. \
|
||||||
|
[drop]: dropped. [erase]: erase the current content. [first]: dropped \
|
||||||
|
if current content is not empty. [merge]: concatenated to the current \
|
||||||
|
content. Default: " ^ !bnotes ^ "" );
|
||||||
|
("-c", Arg.Set just_comp, " Only compiling");
|
||||||
|
("-cg", Arg.Set Db1link.do_consang, " Compute consanguinity");
|
||||||
|
( "-ds",
|
||||||
|
Arg.Set_string Db1link.default_source,
|
||||||
|
"<str> Set the source field for persons and families without source data"
|
||||||
|
);
|
||||||
|
("-f", Arg.Set force, " Remove database if already existing");
|
||||||
|
("-mem", Arg.Set Outbase.save_mem, " Save memory, but slower");
|
||||||
|
("-nc", Arg.Clear Db1link.do_check, " No consistency check");
|
||||||
|
("-nofail", Arg.Set Gwcomp.no_fail, " No failure in case of error");
|
||||||
|
("-nolock", Arg.Set Lock.no_lock_flag, " Do not lock database");
|
||||||
|
( "-nopicture",
|
||||||
|
Arg.Set Gwcomp.no_picture,
|
||||||
|
" Do not create associative pictures" );
|
||||||
|
( "-o",
|
||||||
|
Arg.Set_string out_file,
|
||||||
|
"<file> Output database (default: a.gwb). Alphanumerics and -" );
|
||||||
|
( "-particles",
|
||||||
|
Arg.Set_string Db1link.particules_file,
|
||||||
|
"<file> Particles file (default = predefined particles)" );
|
||||||
|
("-q", Arg.Clear Mutil.verbose, " Quiet");
|
||||||
|
("-sep", Arg.Set separate, " Separate all persons in next file");
|
||||||
|
("-sh", Arg.Set_int shift, "<int> Shift all persons numbers in next files");
|
||||||
|
("-stats", Arg.Set Db1link.pr_stats, " Print statistics");
|
||||||
|
("-v", Arg.Set Mutil.verbose, " Verbose");
|
||||||
|
]
|
||||||
|
|> List.sort compare |> Arg.align
|
||||||
|
|
||||||
|
let anonfun x =
|
||||||
|
let bn = !bnotes in
|
||||||
|
let sep = !separate in
|
||||||
|
if Filename.check_suffix x ".gw" then ()
|
||||||
|
else if Filename.check_suffix x ".gwo" then ()
|
||||||
|
else raise (Arg.Bad ("Don't know what to do with \"" ^ x ^ "\""));
|
||||||
|
separate := false;
|
||||||
|
bnotes := "merge";
|
||||||
|
files := (x, sep, bn, !shift) :: !files
|
||||||
|
|
||||||
|
let errmsg =
|
||||||
|
"Usage: gwc [options] [files]\n\
|
||||||
|
where [files] are a list of files:\n\
|
||||||
|
\ source files end with .gw\n\
|
||||||
|
\ object files end with .gwo\n\
|
||||||
|
and [options] are:"
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
Mutil.verbose := false;
|
||||||
|
Arg.parse speclist anonfun errmsg;
|
||||||
|
if not (Mutil.good_name (Filename.basename !out_file)) then (
|
||||||
|
(* Util.transl conf not available !*)
|
||||||
|
Printf.eprintf "The database name \"%s\" contains a forbidden character./n"
|
||||||
|
!out_file;
|
||||||
|
Printf.eprintf "Allowed characters: a..z, A..Z, 0..9, -";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
Secure.set_base_dir (Filename.dirname !out_file);
|
||||||
|
let gwo = ref [] in
|
||||||
|
List.iter
|
||||||
|
(fun (x, separate, bnotes, shift) ->
|
||||||
|
if Filename.check_suffix x ".gw" then (
|
||||||
|
(try Gwcomp.comp_families x
|
||||||
|
with e ->
|
||||||
|
Printf.eprintf "File \"%s\", line %d:\n" x !line_cnt;
|
||||||
|
raise e);
|
||||||
|
gwo := (x ^ "o", separate, bnotes, shift) :: !gwo)
|
||||||
|
else if Filename.check_suffix x ".gwo" then
|
||||||
|
gwo := (x, separate, bnotes, shift) :: !gwo
|
||||||
|
else raise (Arg.Bad ("Don't know what to do with \"" ^ x ^ "\"")))
|
||||||
|
(List.rev !files);
|
||||||
|
if not !just_comp then (
|
||||||
|
let bdir =
|
||||||
|
if Filename.check_suffix !out_file ".gwb" then !out_file
|
||||||
|
else !out_file ^ ".gwb"
|
||||||
|
in
|
||||||
|
if (not !force) && Sys.file_exists bdir then (
|
||||||
|
Printf.eprintf
|
||||||
|
"The database \"%s\" already exists. Use option -f to overwrite it."
|
||||||
|
!out_file;
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
Lock.control (Mutil.lock_file !out_file)
|
||||||
|
false ~onerror:Lock.print_error_and_exit (fun () ->
|
||||||
|
let bdir =
|
||||||
|
if Filename.check_suffix !out_file ".gwb" then !out_file
|
||||||
|
else !out_file ^ ".gwb"
|
||||||
|
in
|
||||||
|
let next_family_fun = next_family_fun_templ (List.rev !gwo) in
|
||||||
|
if Db1link.link next_family_fun bdir then ()
|
||||||
|
else (
|
||||||
|
Printf.eprintf "*** database not created\n";
|
||||||
|
flush stderr;
|
||||||
|
exit 2)))
|
||||||
|
|
||||||
|
let _ = main ()
|
1329
bin/gwc/gwcomp.ml
Normal file
1329
bin/gwc/gwcomp.ml
Normal file
File diff suppressed because it is too large
Load Diff
99
bin/gwc/gwcomp.mli
Normal file
99
bin/gwc/gwcomp.mli
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
(* Copyright (c) 2007-2008 INRIA *)
|
||||||
|
|
||||||
|
open Def
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
type key = { pk_first_name : string; pk_surname : string; pk_occ : int }
|
||||||
|
(** Key to refer a person's definition *)
|
||||||
|
|
||||||
|
(** Represents a person in .gw file. It could be either reference to a person
|
||||||
|
(only key elements provided) or definition (all information provided). *)
|
||||||
|
type somebody =
|
||||||
|
| Undefined of key (** Reference to person *)
|
||||||
|
| Defined of (iper, iper, string) gen_person (** Person's definition *)
|
||||||
|
|
||||||
|
(** Blocks that could appear in .gw file. *)
|
||||||
|
type gw_syntax =
|
||||||
|
| Family of
|
||||||
|
somebody gen_couple
|
||||||
|
* sex
|
||||||
|
* sex
|
||||||
|
* (somebody * sex) list
|
||||||
|
* (string gen_fam_event_name
|
||||||
|
* cdate
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* (somebody * sex * witness_kind) list)
|
||||||
|
list
|
||||||
|
* ((iper, iper, string) gen_person, ifam, string) gen_family
|
||||||
|
* (iper, iper, string) gen_person gen_descend
|
||||||
|
(** Family definition block. Contains:
|
||||||
|
- Family couple (father's and mother's definition/reference)
|
||||||
|
- Father's sex
|
||||||
|
- Mother's sex
|
||||||
|
- List of witnesses definition/reference with their sex.
|
||||||
|
- List of information about every family event (name, date,
|
||||||
|
place, reason, source, notes and witnesses)
|
||||||
|
- Family definition
|
||||||
|
- Children (descendants) *)
|
||||||
|
| Notes of key * string
|
||||||
|
(** Block that defines personal notes. First element represents
|
||||||
|
reference to person. Second is note's content. *)
|
||||||
|
| Relations of somebody * sex * (somebody, string) gen_relation list
|
||||||
|
(** Block that defines relations of a person with someone outisde of
|
||||||
|
family block. Contains:
|
||||||
|
- Concerned person definition/reference
|
||||||
|
- Sex of person
|
||||||
|
- List of his relations. *)
|
||||||
|
| Pevent of
|
||||||
|
somebody
|
||||||
|
* sex
|
||||||
|
* (string gen_pers_event_name
|
||||||
|
* cdate
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* string
|
||||||
|
* (somebody * sex * witness_kind) list)
|
||||||
|
list
|
||||||
|
(** Block that defines events of a person. Specific to gwplus format. Contains:
|
||||||
|
- Concerned person definition/reference
|
||||||
|
- Sex of person
|
||||||
|
- List of information about every personal event (name, date,
|
||||||
|
place, reason, source, notes and witnesses)*)
|
||||||
|
| Bnotes of string * string
|
||||||
|
(** Block that defines database notes and extended pages.
|
||||||
|
First string represents name of extended page ("" for
|
||||||
|
database notes, only one for file).
|
||||||
|
Second is note's or page's content. *)
|
||||||
|
| Wnotes of string * string
|
||||||
|
(** Block that defines wizard notes.
|
||||||
|
First string represents wizard's id.
|
||||||
|
Second is note's content. *)
|
||||||
|
|
||||||
|
val magic_gwo : string
|
||||||
|
(** .gwo file header *)
|
||||||
|
|
||||||
|
val line_cnt : int ref
|
||||||
|
(** Line counter while reading .gw file *)
|
||||||
|
|
||||||
|
val no_fail : bool ref
|
||||||
|
(** Do not raise exception if syntax error occured.
|
||||||
|
Instead print error information on stdout *)
|
||||||
|
|
||||||
|
val no_picture : bool ref
|
||||||
|
(** Save path to the images *)
|
||||||
|
|
||||||
|
val create_all_keys : bool ref
|
||||||
|
(** Forces to create all the keys for every persons (even for ? ?).
|
||||||
|
Enabled for gwplus format. *)
|
||||||
|
|
||||||
|
val comp_families : string -> unit
|
||||||
|
(** Compile .gw file and save result to corresponding .gwo *)
|
||||||
|
|
||||||
|
(* Ajout pour l'API *)
|
||||||
|
|
||||||
|
val date_of_string : string -> int -> date option
|
||||||
|
(** Parses [Def.date] from string that starts at pos [i] inside [s] *)
|
79
bin/gwd/README.md
Normal file
79
bin/gwd/README.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# gwd - The GeneWeb daemon
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
### Disclaimer
|
||||||
|
|
||||||
|
Plugin system allow you to run **ANY** piece of code as a handler
|
||||||
|
for any requests.
|
||||||
|
|
||||||
|
It means that you could run **harmful** code if you do not control the source
|
||||||
|
of compiled.
|
||||||
|
|
||||||
|
i.e you should not run plugins using the `-unsafe_*` options unless
|
||||||
|
you are developping your own plugin.
|
||||||
|
|
||||||
|
*Reliable* plugins are the ones accepted by `-plugin` and `-plugins` option.
|
||||||
|
|
||||||
|
*Reliable* means that the compiled code and assets you load are the one used
|
||||||
|
in official distribution. It does not make the code safe, but you
|
||||||
|
know what is actually running on your machine by reading the source code.
|
||||||
|
|
||||||
|
### How to load a plugin in gwd
|
||||||
|
|
||||||
|
If you want to control what plugins `gwd` loads, and control the order,
|
||||||
|
use the `-plugin path/to/foo` option, and it will load
|
||||||
|
`path/to/foo/plugin_foo.cmxs` file.
|
||||||
|
|
||||||
|
A simpler solution is to use `-plugins path/to/plugins/` and let
|
||||||
|
`gwd` load all available plugins in the directory, using `META` files
|
||||||
|
in order to load the plugins in the right order.
|
||||||
|
|
||||||
|
### How to write a plugin for gwd
|
||||||
|
|
||||||
|
It is expected that you follow a simple architecture when writing a
|
||||||
|
plugin for `gwd`.
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/
|
||||||
|
META
|
||||||
|
assets/
|
||||||
|
dune
|
||||||
|
plugin_foo.cmxs
|
||||||
|
```
|
||||||
|
|
||||||
|
- `META`: describe your plugin metadata such as name, and dependencies.
|
||||||
|
- `assets/`: every static assets needed by you plugin (css, js, images, etc...)
|
||||||
|
- `plugin_foo.cmxs`: the which will load handlers.
|
||||||
|
|
||||||
|
The `dune` file must define the `plugin` `alias`.
|
||||||
|
|
||||||
|
```
|
||||||
|
(executable
|
||||||
|
(name plugin_foo)
|
||||||
|
(modes (native plugin))
|
||||||
|
)
|
||||||
|
|
||||||
|
(alias (name plugin) (deps plugin_foo.cmxs))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Allowing gwd to run your plugin
|
||||||
|
|
||||||
|
Anything in GeneWeb distribution will be registered in whitelist, and
|
||||||
|
gwd will check file integrity before loading the plugin.
|
||||||
|
|
||||||
|
You can still execute an untrusted plugin with `-unsafe_plugin`
|
||||||
|
and `-unsafe_plugins` options.
|
||||||
|
|
||||||
|
#### META file
|
||||||
|
|
||||||
|
```
|
||||||
|
version: version of your plugin
|
||||||
|
maintainers: comma-seperated list of plugin maintainers
|
||||||
|
depends: comma-seperated list of other plugins needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stability
|
||||||
|
|
||||||
|
Plugin system is new and still under heavy test and development.
|
||||||
|
API should not be considered stable yet.
|
42
bin/gwd/base64.ml
Normal file
42
bin/gwd/base64.ml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
(* $Id: base64.ml,v 5.2 2007-01-19 01:53:16 ddr Exp $ *)
|
||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
(* For basic credentials only *)
|
||||||
|
(* Encoding is [A-Z][a-z][0-9]+/= *)
|
||||||
|
(* 3 chars = 24 bits = 4 * 6-bit groups -> 4 chars *)
|
||||||
|
|
||||||
|
(* Init the index *)
|
||||||
|
let index64 =
|
||||||
|
let index64 = Array.make 128 0 in
|
||||||
|
for i = 0 to 25 do
|
||||||
|
index64.(i + Char.code 'A') <- i
|
||||||
|
done;
|
||||||
|
for i = 0 to 25 do
|
||||||
|
index64.(i + Char.code 'a') <- i + 26
|
||||||
|
done;
|
||||||
|
for i = 0 to 9 do
|
||||||
|
index64.(i + Char.code '0') <- i + 52
|
||||||
|
done;
|
||||||
|
index64.(Char.code '+') <- 62;
|
||||||
|
index64.(Char.code '/') <- 63;
|
||||||
|
index64
|
||||||
|
|
||||||
|
let decode s =
|
||||||
|
let rpos = ref 0 and wpos = ref 0 and len = String.length s in
|
||||||
|
let res = Bytes.create (len / 4 * 3) in
|
||||||
|
while !rpos < len do
|
||||||
|
let v1 = index64.(Char.code s.[!rpos]) in
|
||||||
|
let v2 = index64.(Char.code s.[!rpos + 1]) in
|
||||||
|
let v3 = index64.(Char.code s.[!rpos + 2]) in
|
||||||
|
let v4 = index64.(Char.code s.[!rpos + 3]) in
|
||||||
|
let i = (v1 lsl 18) lor (v2 lsl 12) lor (v3 lsl 6) lor v4 in
|
||||||
|
Bytes.set res !wpos (Char.chr (i lsr 16));
|
||||||
|
Bytes.set res (!wpos + 1) (Char.chr ((i lsr 8) land 0xFF));
|
||||||
|
Bytes.set res (!wpos + 2) (Char.chr (i land 0xFF));
|
||||||
|
rpos := !rpos + 4;
|
||||||
|
wpos := !wpos + 3
|
||||||
|
done;
|
||||||
|
let cut =
|
||||||
|
if s.[len - 1] = '=' then if s.[len - 2] = '=' then 2 else 1 else 0
|
||||||
|
in
|
||||||
|
Bytes.sub_string res 0 (Bytes.length res - cut)
|
2
bin/gwd/base64.mli
Normal file
2
bin/gwd/base64.mli
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
val decode : string -> string
|
||||||
|
(** Decode {i Base64} binary-to-text encoding used at the moment of basic autorization *)
|
49
bin/gwd/dune.in
Normal file
49
bin/gwd/dune.in
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
(rule
|
||||||
|
(target gwdPluginMD5.ml)
|
||||||
|
(deps
|
||||||
|
(alias_rec %{project_root}/plugins/plugin)
|
||||||
|
(:maker mk_gwdPluginMD5.ml)
|
||||||
|
)
|
||||||
|
(action (with-stdout-to %{target} (run ocaml %{maker} %{project_root}/plugins)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(library
|
||||||
|
(name gwd_lib)
|
||||||
|
(public_name geneweb.gwd_lib)
|
||||||
|
(wrapped true)
|
||||||
|
(libraries
|
||||||
|
geneweb
|
||||||
|
wserver
|
||||||
|
%%%GWDB_PKG%%%
|
||||||
|
%%%SOSA_PKG%%%
|
||||||
|
%%%SYSLOG_PKG%%%
|
||||||
|
)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(modules gwdLog gwdPlugin request)
|
||||||
|
)
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name gwd)
|
||||||
|
(public_name geneweb.gwd)
|
||||||
|
(flags -linkall)
|
||||||
|
(libraries
|
||||||
|
dynlink
|
||||||
|
geneweb
|
||||||
|
gwd_lib
|
||||||
|
str
|
||||||
|
unix
|
||||||
|
uri
|
||||||
|
wserver
|
||||||
|
%%%GWDB_PKG%%%
|
||||||
|
%%%SOSA_PKG%%%
|
||||||
|
)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(modules
|
||||||
|
base64
|
||||||
|
gwd
|
||||||
|
gwdPluginDep
|
||||||
|
gwdPluginMD5
|
||||||
|
gwdPluginMETA
|
||||||
|
robot
|
||||||
|
)
|
||||||
|
)
|
2139
bin/gwd/gwd.ml
Normal file
2139
bin/gwd/gwd.ml
Normal file
File diff suppressed because it is too large
Load Diff
80
bin/gwd/gwdLog.ml
Normal file
80
bin/gwd/gwdLog.ml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
let verbosity = ref 7
|
||||||
|
let debug = ref false
|
||||||
|
|
||||||
|
let oc : out_channel option ref = ref None
|
||||||
|
|
||||||
|
let log fn =
|
||||||
|
match !oc with
|
||||||
|
| Some oc -> fn oc
|
||||||
|
| None -> ()
|
||||||
|
|
||||||
|
type level =
|
||||||
|
[ `LOG_ALERT
|
||||||
|
| `LOG_CRIT
|
||||||
|
| `LOG_DEBUG
|
||||||
|
| `LOG_EMERG
|
||||||
|
| `LOG_ERR
|
||||||
|
| `LOG_INFO
|
||||||
|
| `LOG_NOTICE
|
||||||
|
| `LOG_WARNING
|
||||||
|
]
|
||||||
|
|
||||||
|
#ifdef SYSLOG
|
||||||
|
let syslog (level : level) msg =
|
||||||
|
let flags = if !debug then [`LOG_PERROR] else [] in
|
||||||
|
if !verbosity
|
||||||
|
>=
|
||||||
|
match level with
|
||||||
|
| `LOG_EMERG -> 0
|
||||||
|
| `LOG_ALERT -> 1
|
||||||
|
| `LOG_CRIT -> 2
|
||||||
|
| `LOG_ERR -> 3
|
||||||
|
| `LOG_WARNING -> 4
|
||||||
|
| `LOG_NOTICE -> 5
|
||||||
|
| `LOG_INFO -> 6
|
||||||
|
| `LOG_DEBUG -> 7
|
||||||
|
then begin
|
||||||
|
let log = Syslog.openlog ~flags @@ Filename.basename @@ Sys.executable_name in
|
||||||
|
Syslog.syslog log level msg ;
|
||||||
|
Syslog.closelog log ;
|
||||||
|
if !debug then Printexc.print_backtrace stderr ;
|
||||||
|
end
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SYSLOG
|
||||||
|
let syslog (level : level) msg =
|
||||||
|
if !verbosity
|
||||||
|
>=
|
||||||
|
match level with
|
||||||
|
| `LOG_EMERG -> 0
|
||||||
|
| `LOG_ALERT -> 1
|
||||||
|
| `LOG_CRIT -> 2
|
||||||
|
| `LOG_ERR -> 3
|
||||||
|
| `LOG_WARNING -> 4
|
||||||
|
| `LOG_NOTICE -> 5
|
||||||
|
| `LOG_INFO -> 6
|
||||||
|
| `LOG_DEBUG -> 7
|
||||||
|
then begin
|
||||||
|
let tm = Unix.(time () |> localtime) in
|
||||||
|
let level =
|
||||||
|
match level with
|
||||||
|
| `LOG_EMERG -> "EMERGENCY"
|
||||||
|
| `LOG_ALERT -> "ALERT"
|
||||||
|
| `LOG_CRIT -> "CRITICAL"
|
||||||
|
| `LOG_ERR -> "ERROR"
|
||||||
|
| `LOG_WARNING -> "WARNING"
|
||||||
|
| `LOG_NOTICE -> "NOTICE"
|
||||||
|
| `LOG_INFO -> "INFO"
|
||||||
|
| `LOG_DEBUG -> "DEBUG"
|
||||||
|
in
|
||||||
|
let print oc = Printf.fprintf oc "[%s]: %s %s\n" (Mutil.sprintf_date tm :> string) level msg in
|
||||||
|
begin match Sys.getenv_opt "GW_SYSLOG_FILE" with
|
||||||
|
| Some fn ->
|
||||||
|
let oc = open_out_gen [ Open_wronly ; Open_creat ; Open_append ] 0o644 fn in
|
||||||
|
print oc ;
|
||||||
|
close_out oc
|
||||||
|
| None -> print stderr
|
||||||
|
end ;
|
||||||
|
if !debug then Printexc.print_backtrace stderr ;
|
||||||
|
end
|
||||||
|
#endif
|
27
bin/gwd/gwdLog.mli
Normal file
27
bin/gwd/gwdLog.mli
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
val verbosity : int ref
|
||||||
|
(** Verbosity level: defines the verbosity level that will
|
||||||
|
allow the [syslog] function to print anything. *)
|
||||||
|
|
||||||
|
val debug : bool ref
|
||||||
|
(** If set to [true], prints backtrace when printing log. *)
|
||||||
|
|
||||||
|
val oc : out_channel option ref
|
||||||
|
(** The output channel in which log is written. *)
|
||||||
|
|
||||||
|
val log : (out_channel -> unit) -> unit
|
||||||
|
(** Prints on [oc] *)
|
||||||
|
|
||||||
|
type level =
|
||||||
|
[ `LOG_EMERG (** Print if `!verbosity >= 0` *)
|
||||||
|
| `LOG_ALERT (** Print if `!verbosity >= 1` *)
|
||||||
|
| `LOG_CRIT (** Print if `!verbosity >= 2` *)
|
||||||
|
| `LOG_ERR (** Print if `!verbosity >= 3` *)
|
||||||
|
| `LOG_WARNING (** Print if `!verbosity >= 4` *)
|
||||||
|
| `LOG_NOTICE (** Print if `!verbosity >= 5` *)
|
||||||
|
| `LOG_INFO (** Print if `!verbosity >= 6` *)
|
||||||
|
| `LOG_DEBUG (** Print if `!verbosity >= 7` *) ]
|
||||||
|
(** The level of log. *)
|
||||||
|
|
||||||
|
val syslog : level -> string -> unit
|
||||||
|
(** [syslog level msg]
|
||||||
|
Prints [msg] on [!oc] depending on the verbosity. *)
|
19
bin/gwd/gwdPlugin.ml
Normal file
19
bin/gwd/gwdPlugin.ml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
open Geneweb
|
||||||
|
|
||||||
|
let assets = ref ""
|
||||||
|
let registered = ref []
|
||||||
|
|
||||||
|
let ht : (string, string * (Config.config -> string option -> bool)) Hashtbl.t =
|
||||||
|
Hashtbl.create 0
|
||||||
|
|
||||||
|
let register ~ns list =
|
||||||
|
assert (not @@ List.mem ns !registered);
|
||||||
|
registered := ns :: !registered;
|
||||||
|
List.iter
|
||||||
|
(fun (m, fn) ->
|
||||||
|
let fn = fn !assets in
|
||||||
|
Hashtbl.add ht m (ns, fn))
|
||||||
|
list
|
||||||
|
|
||||||
|
let se : (string * (Config.config -> string option -> unit)) list ref = ref []
|
||||||
|
let register_se ~ns fn = Mutil.list_ref_append se (ns, fn !assets)
|
50
bin/gwd/gwdPlugin.mli
Normal file
50
bin/gwd/gwdPlugin.mli
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
val assets : string ref
|
||||||
|
(** When dynamically loading a plugin, this variable contains
|
||||||
|
the path of the assets directory associated to the plugin
|
||||||
|
being currently loaded.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val register :
|
||||||
|
ns:string ->
|
||||||
|
(string * (string -> Geneweb.Config.config -> string option -> bool)) list ->
|
||||||
|
unit
|
||||||
|
(** [register ~ns handlers] register modes handlers of a plugin.
|
||||||
|
|
||||||
|
[ns] is the namespace of the plugin (i.e. its name)
|
||||||
|
|
||||||
|
[handler] is a associative list of handler.
|
||||||
|
The key is the mode (the `m` GET/POST parameter).
|
||||||
|
The value is the handler itself. The difference between a plugin
|
||||||
|
handler and default gwd's handlers (the ones in request.ml) is that
|
||||||
|
a plugin handler takes an extra (first) argument being
|
||||||
|
the path of the asset directory associated to this plugin
|
||||||
|
and returns a boolean.
|
||||||
|
|
||||||
|
If the handler returns [true], it means that it actually processed
|
||||||
|
the request. If is is [false], [gwd] must try another plugin handler to
|
||||||
|
treat the request. If no plugin is suitable, gwd's default handler
|
||||||
|
must be used, or fail if it does not exists.
|
||||||
|
|
||||||
|
Handlers can overwrite pre-existing modes or create new ones.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val ht :
|
||||||
|
(string, string * (Geneweb.Config.config -> string option -> bool)) Hashtbl.t
|
||||||
|
(** Table of handlers registered by plugins. *)
|
||||||
|
|
||||||
|
val register_se :
|
||||||
|
ns:string ->
|
||||||
|
(string -> Geneweb.Config.config -> string option -> unit) ->
|
||||||
|
unit
|
||||||
|
(** [register_se ~ns hook] register a plugin hook (side effect function).
|
||||||
|
|
||||||
|
If enabled, hooks are executed before the request handlers, in the
|
||||||
|
order of registration (first registred = first executed).
|
||||||
|
|
||||||
|
For exemple, a plugin could be to change the [conf] output to print everything
|
||||||
|
in a buffer and apply a transformation to the resulting document before actually
|
||||||
|
sending it to the client.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val se : (string * (Geneweb.Config.config -> string option -> unit)) list ref
|
||||||
|
(** Table of hooks registered by plugins. *)
|
122
bin/gwd/gwdPluginDep.ml
Normal file
122
bin/gwd/gwdPluginDep.ml
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
(* https://github.com/dmbaturin/ocaml-tsort *)
|
||||||
|
(* Authors: Daniil Baturin (2019), Martin Jambon (2020). *)
|
||||||
|
(* See LICENSE at the end of the file *)
|
||||||
|
|
||||||
|
(* Adapted to GeneWeb by Julien Sagot *)
|
||||||
|
|
||||||
|
type 'a sort_result = Sorted of 'a list | ErrorCycle of 'a list
|
||||||
|
|
||||||
|
(* Finds "isolated" nodes,
|
||||||
|
that is, nodes that have no dependencies *)
|
||||||
|
let find_isolated_nodes hash =
|
||||||
|
let aux id deps acc = match deps with [] -> id :: acc | _ -> acc in
|
||||||
|
Hashtbl.fold aux hash []
|
||||||
|
|
||||||
|
(* Takes a node name list and removes all those nodes from a hash *)
|
||||||
|
let remove_nodes nodes hash = List.iter (Hashtbl.remove hash) nodes
|
||||||
|
|
||||||
|
(* Walks through a node:dependencies hash and removes a dependency
|
||||||
|
from all nodes that have it in their dependency lists *)
|
||||||
|
let remove_dependency hash dep =
|
||||||
|
let aux dep hash id =
|
||||||
|
let deps = Hashtbl.find hash id in
|
||||||
|
let deps = List.filter (( <> ) dep) deps in
|
||||||
|
Hashtbl.remove hash id;
|
||||||
|
Hashtbl.add hash id deps
|
||||||
|
in
|
||||||
|
let ids = Hashtbl.fold (fun k _ a -> k :: a) hash [] in
|
||||||
|
List.iter (aux dep hash) ids
|
||||||
|
|
||||||
|
(* Deduplicate list items. *)
|
||||||
|
let deduplicate l =
|
||||||
|
let tbl = Hashtbl.create (List.length l) in
|
||||||
|
List.fold_left
|
||||||
|
(fun acc x ->
|
||||||
|
if Hashtbl.mem tbl x then acc
|
||||||
|
else (
|
||||||
|
Hashtbl.add tbl x ();
|
||||||
|
x :: acc))
|
||||||
|
[] l
|
||||||
|
|> List.rev
|
||||||
|
|
||||||
|
(*
|
||||||
|
Append missing nodes to the graph, in the order in which they were
|
||||||
|
encountered. This particular order doesn't have to be guaranteed by the
|
||||||
|
API but seems nice to have.
|
||||||
|
*)
|
||||||
|
let add_missing_nodes graph_l graph =
|
||||||
|
let missing =
|
||||||
|
List.fold_left
|
||||||
|
(fun acc (_, vl) ->
|
||||||
|
List.fold_left
|
||||||
|
(fun acc v ->
|
||||||
|
if not (Hashtbl.mem graph v) then (v, []) :: acc else acc)
|
||||||
|
acc vl)
|
||||||
|
[] graph_l
|
||||||
|
|> List.rev
|
||||||
|
in
|
||||||
|
List.iter (fun (v, vl) -> Hashtbl.replace graph v vl) missing;
|
||||||
|
graph_l @ missing
|
||||||
|
|
||||||
|
(* The Kahn's algorithm:
|
||||||
|
1. Find nodes that have no dependencies ("isolated") and remove them from
|
||||||
|
the graph hash.
|
||||||
|
Add them to the initial sorted nodes list and the list of isolated
|
||||||
|
nodes for the first sorting pass.
|
||||||
|
2. For every isolated node, walk through the remaining nodes and
|
||||||
|
remove it from their dependency list.
|
||||||
|
Nodes that only depended on it now have empty dependency lists.
|
||||||
|
3. Find all nodes with empty dependency lists and append them to the sorted
|
||||||
|
nodes list _and_ the list of isolated nodes to use for the next step
|
||||||
|
4. Repeat until the list of isolated nodes is empty
|
||||||
|
5. If the graph hash is still not empty, it means there is a cycle.
|
||||||
|
*)
|
||||||
|
let sort nodes =
|
||||||
|
let rec sorting_loop deps hash acc =
|
||||||
|
match deps with
|
||||||
|
| [] -> acc
|
||||||
|
| dep :: deps ->
|
||||||
|
let () = remove_dependency hash dep in
|
||||||
|
let isolated_nodes = find_isolated_nodes hash in
|
||||||
|
let () = remove_nodes isolated_nodes hash in
|
||||||
|
sorting_loop
|
||||||
|
(List.append deps isolated_nodes)
|
||||||
|
hash
|
||||||
|
(List.append acc isolated_nodes)
|
||||||
|
in
|
||||||
|
let nodes_hash =
|
||||||
|
let tbl = Hashtbl.create 32 in
|
||||||
|
List.iter (fun (k, v) -> Hashtbl.add tbl k v) nodes;
|
||||||
|
tbl
|
||||||
|
in
|
||||||
|
let _nodes = add_missing_nodes nodes nodes_hash in
|
||||||
|
let base_nodes = find_isolated_nodes nodes_hash in
|
||||||
|
let () = remove_nodes base_nodes nodes_hash in
|
||||||
|
let sorted_node_ids = sorting_loop base_nodes nodes_hash [] in
|
||||||
|
let sorted_node_ids = List.append base_nodes sorted_node_ids in
|
||||||
|
let remaining_ids = Hashtbl.fold (fun k _ a -> k :: a) nodes_hash [] in
|
||||||
|
match remaining_ids with
|
||||||
|
| [] -> Sorted sorted_node_ids
|
||||||
|
| _ -> ErrorCycle remaining_ids
|
||||||
|
|
||||||
|
(* MIT License *)
|
||||||
|
|
||||||
|
(* Copyright (c) 2019 Daniil Baturin *)
|
||||||
|
|
||||||
|
(* Permission is hereby granted, free of charge, to any person obtaining a copy *)
|
||||||
|
(* of this software and associated documentation files (the "Software"), to deal *)
|
||||||
|
(* in the Software without restriction, including without limitation the rights *)
|
||||||
|
(* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *)
|
||||||
|
(* copies of the Software, and to permit persons to whom the Software is *)
|
||||||
|
(* furnished to do so, subject to the following conditions: *)
|
||||||
|
|
||||||
|
(* The above copyright notice and this permission notice shall be included in all *)
|
||||||
|
(* copies or substantial portions of the Software. *)
|
||||||
|
|
||||||
|
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *)
|
||||||
|
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
|
||||||
|
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *)
|
||||||
|
(* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *)
|
||||||
|
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *)
|
||||||
|
(* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *)
|
||||||
|
(* SOFTWARE. *)
|
9
bin/gwd/gwdPluginDep.mli
Normal file
9
bin/gwd/gwdPluginDep.mli
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
type 'a sort_result = Sorted of 'a list | ErrorCycle of 'a list
|
||||||
|
|
||||||
|
val sort : ('a * 'a list) list -> 'a sort_result
|
||||||
|
(** Given a list of elements (in this case, plugins) and their dependencies,
|
||||||
|
tries to compute a valid order `l` and return `Sorted l` .
|
||||||
|
If there is a cycle, returns `ErrorCycle l'` where `l'` is a dependency
|
||||||
|
cycle.
|
||||||
|
Uses Kahn's algorithm for cycle detection.
|
||||||
|
*)
|
1
bin/gwd/gwdPluginMD5.mli
Normal file
1
bin/gwd/gwdPluginMD5.mli
Normal file
@ -0,0 +1 @@
|
|||||||
|
val allowed : string -> bool
|
30
bin/gwd/gwdPluginMETA.ml
Normal file
30
bin/gwd/gwdPluginMETA.ml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
type meta = {
|
||||||
|
version : string;
|
||||||
|
maintainers : string list;
|
||||||
|
depends : string list;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parse fname =
|
||||||
|
let ic = open_in fname in
|
||||||
|
let rec loop meta =
|
||||||
|
match input_line ic with
|
||||||
|
| exception End_of_file ->
|
||||||
|
close_in ic;
|
||||||
|
meta
|
||||||
|
| s -> (
|
||||||
|
match String.index_opt s ':' with
|
||||||
|
| None -> loop meta
|
||||||
|
| Some i -> (
|
||||||
|
let v =
|
||||||
|
String.trim @@ String.sub s (i + 1) (String.length s - i - 1)
|
||||||
|
in
|
||||||
|
let split_and_trim v =
|
||||||
|
List.map String.trim @@ String.split_on_char ',' v
|
||||||
|
in
|
||||||
|
match String.trim @@ String.sub s 0 i with
|
||||||
|
| "depends" -> loop { meta with depends = split_and_trim v }
|
||||||
|
| "maintainers" -> loop { meta with maintainers = split_and_trim v }
|
||||||
|
| "version" -> loop { meta with version = v }
|
||||||
|
| _ -> loop meta))
|
||||||
|
in
|
||||||
|
loop { version = ""; maintainers = []; depends = [] }
|
7
bin/gwd/gwdPluginMETA.mli
Normal file
7
bin/gwd/gwdPluginMETA.mli
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
type meta = {
|
||||||
|
version : string;
|
||||||
|
maintainers : string list;
|
||||||
|
depends : string list;
|
||||||
|
}
|
||||||
|
|
||||||
|
val parse : string -> meta
|
71
bin/gwd/mk_gwdPluginMD5.ml
Normal file
71
bin/gwd/mk_gwdPluginMD5.ml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
let md5 plugin =
|
||||||
|
let files =
|
||||||
|
let rec loop result = function
|
||||||
|
| [] -> result
|
||||||
|
| f :: fs ->
|
||||||
|
if Sys.file_exists f then
|
||||||
|
if String.get f (String.length f - 1) = '~' then loop result fs
|
||||||
|
else if Sys.is_directory f then
|
||||||
|
Sys.readdir f |> Array.to_list
|
||||||
|
|> List.rev_map (Filename.concat f)
|
||||||
|
|> List.rev_append fs |> loop result
|
||||||
|
else loop (f :: result) fs
|
||||||
|
else loop result fs
|
||||||
|
in
|
||||||
|
loop []
|
||||||
|
[
|
||||||
|
Filename.concat plugin @@ "plugin_" ^ Filename.basename plugin ^ ".cmxs";
|
||||||
|
Filename.concat plugin "assets";
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let files = List.sort compare files in
|
||||||
|
let b = Buffer.create 1024 in
|
||||||
|
List.iter
|
||||||
|
(fun f -> Digest.file f |> Digest.to_hex |> Buffer.add_string b)
|
||||||
|
files;
|
||||||
|
Buffer.contents b |> Digest.string |> Digest.to_hex
|
||||||
|
|
||||||
|
let () =
|
||||||
|
print_endline
|
||||||
|
{|let md5 plugin =
|
||||||
|
let files =
|
||||||
|
let rec loop result = function
|
||||||
|
| [] -> result
|
||||||
|
| f :: fs ->
|
||||||
|
if Sys.file_exists f
|
||||||
|
then
|
||||||
|
if String.get f (String.length f - 1) = '~'
|
||||||
|
then loop result fs
|
||||||
|
else if Sys.is_directory f
|
||||||
|
then
|
||||||
|
Sys.readdir f
|
||||||
|
|> Array.to_list
|
||||||
|
|> List.rev_map (Filename.concat f)
|
||||||
|
|> List.rev_append fs
|
||||||
|
|> loop result
|
||||||
|
else (loop (f :: result) fs)
|
||||||
|
else (loop result fs)
|
||||||
|
in
|
||||||
|
loop [] [ Filename.concat plugin @@ "plugin_" ^ Filename.basename plugin ^ ".cmxs"
|
||||||
|
; Filename.concat plugin "assets"
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let files = List.sort compare files in
|
||||||
|
let b = Buffer.create 1024 in
|
||||||
|
List.iter begin fun f ->
|
||||||
|
Digest.file f
|
||||||
|
|> Digest.to_hex
|
||||||
|
|> Buffer.add_string b
|
||||||
|
end files ;
|
||||||
|
Buffer.contents b
|
||||||
|
|> Digest.string
|
||||||
|
|> Digest.to_hex
|
||||||
|
|};
|
||||||
|
print_endline {|let allowed p = match Filename.basename p with|};
|
||||||
|
Array.iter
|
||||||
|
(fun p ->
|
||||||
|
print_endline
|
||||||
|
@@ Printf.sprintf {||"%s" -> md5 p = "%s"|} p
|
||||||
|
(md5 @@ Filename.concat Sys.argv.(1) p))
|
||||||
|
(Sys.readdir Sys.argv.(1));
|
||||||
|
print_endline {||_ -> false|}
|
835
bin/gwd/request.ml
Normal file
835
bin/gwd/request.ml
Normal file
@ -0,0 +1,835 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
open Geneweb
|
||||||
|
open Config
|
||||||
|
open Def
|
||||||
|
open Gwdb
|
||||||
|
open Util
|
||||||
|
|
||||||
|
let person_is_std_key conf base p k =
|
||||||
|
let k = Name.strip_lower k in
|
||||||
|
if k = Name.strip_lower (p_first_name base p ^ " " ^ p_surname base p) then
|
||||||
|
true
|
||||||
|
else if
|
||||||
|
List.exists (fun n -> Name.strip n = k)
|
||||||
|
(person_misc_names base p (nobtit conf base))
|
||||||
|
then
|
||||||
|
true
|
||||||
|
else false
|
||||||
|
|
||||||
|
let select_std_eq conf base pl k =
|
||||||
|
List.fold_right
|
||||||
|
(fun p pl -> if person_is_std_key conf base p k then p :: pl else pl) pl
|
||||||
|
[]
|
||||||
|
|
||||||
|
let find_all conf base an =
|
||||||
|
let sosa_ref = Util.find_sosa_ref conf base in
|
||||||
|
let sosa_nb = try Some (Sosa.of_string an) with _ -> None in
|
||||||
|
match sosa_ref, sosa_nb with
|
||||||
|
| Some p, Some n ->
|
||||||
|
if n <> Sosa.zero then
|
||||||
|
match Util.branch_of_sosa conf base n p with
|
||||||
|
Some (p :: _) -> [p], true
|
||||||
|
| _ -> [], false
|
||||||
|
else [], false
|
||||||
|
| _ ->
|
||||||
|
let acc = SearchName.search_by_key conf base an in
|
||||||
|
if acc <> [] then acc, false
|
||||||
|
else
|
||||||
|
( SearchName.search_key_aux begin fun conf base acc an ->
|
||||||
|
let spl = select_std_eq conf base acc an in
|
||||||
|
if spl = [] then
|
||||||
|
if acc = [] then SearchName.search_by_name conf base an
|
||||||
|
else acc
|
||||||
|
else spl
|
||||||
|
end conf base an
|
||||||
|
, false )
|
||||||
|
|
||||||
|
let relation_print conf base p =
|
||||||
|
let p1 =
|
||||||
|
match p_getenv conf.senv "ei" with
|
||||||
|
| Some i ->
|
||||||
|
conf.senv <- [] ;
|
||||||
|
let i = iper_of_string i in
|
||||||
|
if Gwdb.iper_exists base i
|
||||||
|
then Some (pget conf base i)
|
||||||
|
else None
|
||||||
|
| None ->
|
||||||
|
match find_person_in_env conf base "1" with
|
||||||
|
| Some p1 ->
|
||||||
|
conf.senv <- [];
|
||||||
|
Some p1
|
||||||
|
| None -> None
|
||||||
|
in
|
||||||
|
RelationDisplay.print conf base p p1
|
||||||
|
|
||||||
|
let specify conf base n pl =
|
||||||
|
let title _ = Output.printf conf "%s : %s" n (transl conf "specify") in
|
||||||
|
let n = Name.crush_lower n in
|
||||||
|
let ptll =
|
||||||
|
List.map
|
||||||
|
(fun p ->
|
||||||
|
let tl = ref [] in
|
||||||
|
let add_tl t =
|
||||||
|
tl :=
|
||||||
|
let rec add_rec =
|
||||||
|
function
|
||||||
|
t1 :: tl1 ->
|
||||||
|
if eq_istr t1.t_ident t.t_ident &&
|
||||||
|
eq_istr t1.t_place t.t_place
|
||||||
|
then
|
||||||
|
t1 :: tl1
|
||||||
|
else t1 :: add_rec tl1
|
||||||
|
| [] -> [t]
|
||||||
|
in
|
||||||
|
add_rec !tl
|
||||||
|
in
|
||||||
|
let compare_and_add t pn =
|
||||||
|
let pn = sou base pn in
|
||||||
|
if Name.crush_lower pn = n then add_tl t
|
||||||
|
else
|
||||||
|
match get_qualifiers p with
|
||||||
|
nn :: _ ->
|
||||||
|
let nn = sou base nn in
|
||||||
|
if Name.crush_lower (pn ^ " " ^ nn) = n then add_tl t
|
||||||
|
| _ -> ()
|
||||||
|
in
|
||||||
|
List.iter
|
||||||
|
(fun t ->
|
||||||
|
match t.t_name, get_public_name p with
|
||||||
|
Tname s, _ -> compare_and_add t s
|
||||||
|
| _, pn when sou base pn <> "" -> compare_and_add t pn
|
||||||
|
| _ -> ())
|
||||||
|
(nobtit conf base p);
|
||||||
|
p, !tl)
|
||||||
|
pl
|
||||||
|
in
|
||||||
|
Hutil.header conf title;
|
||||||
|
Hutil.print_link_to_welcome conf true;
|
||||||
|
(* Si on est dans un calcul de parenté, on affiche *)
|
||||||
|
(* l'aide sur la sélection d'un individu. *)
|
||||||
|
Util.print_tips_relationship conf;
|
||||||
|
Output.print_sstring conf "<ul>\n";
|
||||||
|
(* Construction de la table des sosa de la base *)
|
||||||
|
let () = SosaCache.build_sosa_ht conf base in
|
||||||
|
List.iter
|
||||||
|
(fun (p, _tl) ->
|
||||||
|
Output.print_sstring conf "<li>\n";
|
||||||
|
SosaCache.print_sosa conf base p true;
|
||||||
|
Update.print_person_parents_and_spouses conf base p;
|
||||||
|
Output.print_sstring conf "</li>\n"
|
||||||
|
) ptll;
|
||||||
|
Output.print_sstring conf "</ul>\n";
|
||||||
|
Hutil.trailer conf
|
||||||
|
|
||||||
|
let incorrect_request ?(comment = "") conf =
|
||||||
|
Hutil.incorrect_request ~comment:comment conf
|
||||||
|
|
||||||
|
let person_selected conf base p =
|
||||||
|
match p_getenv conf.senv "em" with
|
||||||
|
Some "R" -> relation_print conf base p
|
||||||
|
| Some _ -> incorrect_request conf ~comment:"error #9"
|
||||||
|
| None -> record_visited conf (get_iper p); Perso.print conf base p
|
||||||
|
|
||||||
|
let person_selected_with_redirect conf base p =
|
||||||
|
match p_getenv conf.senv "em" with
|
||||||
|
| Some "R" -> relation_print conf base p
|
||||||
|
| Some _ -> incorrect_request conf ~comment:"error #8"
|
||||||
|
| None ->
|
||||||
|
Wserver.http_redirect_temporarily
|
||||||
|
(commd conf ^^^ Util.acces conf base p :> string)
|
||||||
|
|
||||||
|
let updmenu_print = Perso.interp_templ "updmenu"
|
||||||
|
|
||||||
|
let very_unknown conf _ =
|
||||||
|
match p_getenv conf.env "n", p_getenv conf.env "p" with
|
||||||
|
| Some sname, Some fname ->
|
||||||
|
let title _ =
|
||||||
|
transl conf "not found"
|
||||||
|
|> Utf8.capitalize_fst
|
||||||
|
|> Output.print_sstring conf ;
|
||||||
|
Output.print_sstring conf (transl conf ":") ;
|
||||||
|
Output.print_sstring conf {| "|} ;
|
||||||
|
Output.print_string conf (Util.escape_html fname) ;
|
||||||
|
Output.print_sstring conf {| |} ;
|
||||||
|
Output.print_string conf (Util.escape_html sname) ;
|
||||||
|
Output.print_sstring conf {|"|} ;
|
||||||
|
in
|
||||||
|
Output.status conf Def.Not_Found;
|
||||||
|
Hutil.rheader conf title;
|
||||||
|
Hutil.print_link_to_welcome conf false;
|
||||||
|
Hutil.trailer conf
|
||||||
|
| _ ->
|
||||||
|
match p_getenv conf.env "i" with
|
||||||
|
| Some i ->
|
||||||
|
let title _ =
|
||||||
|
Output.print_sstring conf "<kbd>" ;
|
||||||
|
Output.print_string conf (Util.escape_html i) ;
|
||||||
|
Output.print_sstring conf "</kbd>" ;
|
||||||
|
Output.print_sstring conf (transl conf ":") ;
|
||||||
|
Output.print_sstring conf " " ;
|
||||||
|
transl conf "not found"
|
||||||
|
|> Utf8.capitalize_fst
|
||||||
|
|> Output.print_sstring conf ;
|
||||||
|
in
|
||||||
|
Output.status conf Def.Not_Found;
|
||||||
|
Hutil.rheader conf title;
|
||||||
|
Hutil.print_link_to_welcome conf false;
|
||||||
|
Hutil.trailer conf
|
||||||
|
| None -> Hutil.incorrect_request conf ~comment:"error #1"
|
||||||
|
|
||||||
|
(* Print Not found page *)
|
||||||
|
let unknown conf n =
|
||||||
|
let title _ =
|
||||||
|
transl conf "not found"
|
||||||
|
|> Utf8.capitalize_fst
|
||||||
|
|> Output.print_sstring conf ;
|
||||||
|
Output.print_sstring conf (transl conf ":") ;
|
||||||
|
Output.print_sstring conf {| "|} ;
|
||||||
|
Output.print_string conf (Util.escape_html n) ;
|
||||||
|
Output.print_sstring conf {|"|} ;
|
||||||
|
in
|
||||||
|
Output.status conf Def.Not_Found;
|
||||||
|
Hutil.rheader conf title;
|
||||||
|
Hutil.print_link_to_welcome conf false;
|
||||||
|
Hutil.trailer conf
|
||||||
|
|
||||||
|
let make_henv conf base =
|
||||||
|
let conf =
|
||||||
|
match Util.find_sosa_ref conf base with
|
||||||
|
| Some p ->
|
||||||
|
let x =
|
||||||
|
let first_name = p_first_name base p in
|
||||||
|
let surname = p_surname base p in
|
||||||
|
if Util.accessible_by_key conf base p first_name surname then
|
||||||
|
[ "pz", Name.lower first_name |> Mutil.encode
|
||||||
|
; "nz", Name.lower surname |> Mutil.encode
|
||||||
|
; "ocz", get_occ p |> string_of_int |> Mutil.encode
|
||||||
|
]
|
||||||
|
else [ "iz", get_iper p |> string_of_iper |> Mutil.encode ]
|
||||||
|
in
|
||||||
|
{ conf with henv = conf.henv @ x }
|
||||||
|
| None -> conf
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
match p_getenv conf.env "dsrc" with
|
||||||
|
| Some "" | None -> conf
|
||||||
|
| Some s -> { conf with henv = conf.henv @ ["dsrc", Mutil.encode s] }
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
match p_getenv conf.env "templ" with
|
||||||
|
| None -> conf
|
||||||
|
| Some s -> { conf with henv = conf.henv @ ["templ", Mutil.encode s] }
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
match Util.p_getenv conf.env "escache" with
|
||||||
|
| Some _ -> { conf with henv = conf.henv @ ["escache", escache_value base] }
|
||||||
|
| None -> conf
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
if Util.p_getenv conf.env "manitou" = Some "off"
|
||||||
|
then { conf with henv = conf.henv @ ["manitou", Adef.encoded "off"] }
|
||||||
|
else conf
|
||||||
|
in
|
||||||
|
let aux param conf =
|
||||||
|
match Util.p_getenv conf.env param with
|
||||||
|
| Some s -> { conf with henv = conf.henv @ [param, Mutil.encode s] }
|
||||||
|
| None -> conf
|
||||||
|
in
|
||||||
|
aux "alwsurn" conf
|
||||||
|
|> aux "pure_xhtml"
|
||||||
|
|> aux "size"
|
||||||
|
|> aux "p_mod"
|
||||||
|
|> aux "wide"
|
||||||
|
|
||||||
|
let special_vars =
|
||||||
|
[ "alwsurn"; "cgl"; "dsrc"; "em"; "ei"; "ep"; "en"; "eoc"; "escache"; "et";
|
||||||
|
"iz"; "long"; "manitou"; "nz"; "ocz";
|
||||||
|
"p_mod"; "pure_xhtml"; "pz"; "size"; "templ"; "wide" ]
|
||||||
|
|
||||||
|
let only_special_env env = List.for_all (fun (x, _) -> List.mem x special_vars) env
|
||||||
|
|
||||||
|
let make_senv conf base =
|
||||||
|
let set_senv conf vm vi =
|
||||||
|
let aux k v conf =
|
||||||
|
if p_getenv conf.env k = Some v
|
||||||
|
then { conf with senv = conf.senv @ [ k, Mutil.encode v ] }
|
||||||
|
else conf
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
{ conf with senv = ["em", vm; "ei", vi] }
|
||||||
|
|> aux "long" "on"
|
||||||
|
in
|
||||||
|
let conf =
|
||||||
|
match p_getenv conf.env "et" with
|
||||||
|
| Some x -> { conf with senv = conf.senv @ ["et", Mutil.encode x] }
|
||||||
|
| _ -> conf
|
||||||
|
in
|
||||||
|
let conf = aux "cgl" "on" conf in
|
||||||
|
let conf =
|
||||||
|
match p_getenv conf.env "bd" with
|
||||||
|
| None | Some ("0" | "") -> conf
|
||||||
|
| Some x -> { conf with senv = conf.senv @ ["bd", Mutil.encode x] }
|
||||||
|
in
|
||||||
|
match p_getenv conf.env "color" with
|
||||||
|
| Some x -> { conf with senv = conf.senv @ ["color", Mutil.encode x] }
|
||||||
|
| _ -> conf
|
||||||
|
in
|
||||||
|
let get x = Util.p_getenv conf.env x in
|
||||||
|
match get "em", get "ei", get "ep", get "en", get "eoc" with
|
||||||
|
| Some vm, Some vi, _, _, _ -> set_senv conf (Mutil.encode vm) (Mutil.encode vi)
|
||||||
|
| Some vm, None, Some vp, Some vn, voco ->
|
||||||
|
let voc =
|
||||||
|
match voco with
|
||||||
|
| Some voc -> (try int_of_string voc with Failure _ -> 0)
|
||||||
|
| None -> 0
|
||||||
|
in
|
||||||
|
let ip =
|
||||||
|
match person_of_key base vp vn voc with
|
||||||
|
| Some ip -> ip
|
||||||
|
| None -> Hutil.incorrect_request conf ~comment:"error #2"; raise Exit
|
||||||
|
in
|
||||||
|
let vi = string_of_iper ip in
|
||||||
|
set_senv conf (Mutil.encode vm) (Mutil.encode vi)
|
||||||
|
| _ -> conf
|
||||||
|
|
||||||
|
let propose_base conf =
|
||||||
|
let title _ = Output.print_sstring conf "Base" in
|
||||||
|
Hutil.header conf title;
|
||||||
|
Output.print_sstring conf {|<ul><li><form method="GET" action="|} ;
|
||||||
|
Output.print_sstring conf conf.indep_command ;
|
||||||
|
Output.print_sstring conf {|">|} ;
|
||||||
|
Output.print_sstring conf {|<input name="b" size="40"> => |} ;
|
||||||
|
Output.print_sstring conf {|<button type="submit" class="btn btn-secondary btn-lg">|} ;
|
||||||
|
transl_nth conf "validate/delete" 0
|
||||||
|
|> Utf8.capitalize_fst
|
||||||
|
|> Output.print_sstring conf ;
|
||||||
|
Output.print_sstring conf "</button></li></ul>";
|
||||||
|
Hutil.trailer conf
|
||||||
|
|
||||||
|
let try_plugin list conf base_name m =
|
||||||
|
let fn =
|
||||||
|
if List.mem "*" list
|
||||||
|
then (fun ( _, fn) -> fn conf base_name)
|
||||||
|
else (fun (ns, fn) -> (List.mem ns conf.forced_plugins || List.mem ns list) && fn conf base_name)
|
||||||
|
in
|
||||||
|
List.exists fn (Hashtbl.find_all GwdPlugin.ht m)
|
||||||
|
|
||||||
|
let w_lock ~onerror fn conf (base_name : string option) =
|
||||||
|
let bfile = Util.bpath (conf.bname ^ ".gwb") in
|
||||||
|
Lock.control
|
||||||
|
(Mutil.lock_file bfile) true
|
||||||
|
~onerror:(fun () -> onerror conf base_name)
|
||||||
|
(fun () -> fn conf base_name)
|
||||||
|
|
||||||
|
let w_base ~none fn conf (bfile : string option) =
|
||||||
|
match bfile with
|
||||||
|
| None -> none conf
|
||||||
|
| Some bfile ->
|
||||||
|
let base = try Some (Gwdb.open_base bfile) with _ -> None in
|
||||||
|
match base with
|
||||||
|
| None -> none conf
|
||||||
|
| Some base ->
|
||||||
|
let conf = make_henv conf base in
|
||||||
|
let conf = make_senv conf base in
|
||||||
|
let conf = match Util.default_sosa_ref conf base with
|
||||||
|
| Some p -> { conf with default_sosa_ref = get_iper p, Some p;
|
||||||
|
nb_of_persons = Gwdb.nb_of_persons base }
|
||||||
|
| None -> { conf with
|
||||||
|
nb_of_persons = Gwdb.nb_of_persons base }
|
||||||
|
in
|
||||||
|
fn conf base
|
||||||
|
|
||||||
|
let w_person ~none fn conf base =
|
||||||
|
match find_person_in_env conf base "" with
|
||||||
|
| Some p -> fn conf base p
|
||||||
|
| _ -> none conf base
|
||||||
|
|
||||||
|
let output_error ?headers ?content conf code =
|
||||||
|
!GWPARAM.output_error ?headers ?content conf code
|
||||||
|
|
||||||
|
let w_wizard fn conf base =
|
||||||
|
if conf.wizard then
|
||||||
|
fn conf base
|
||||||
|
else if conf.just_friend_wizard then
|
||||||
|
output_error conf Def.Forbidden
|
||||||
|
else
|
||||||
|
(* FIXME: send authentification headers *)
|
||||||
|
output_error conf Def.Unauthorized
|
||||||
|
|
||||||
|
let treat_request =
|
||||||
|
let w_lock = w_lock ~onerror:(fun conf _ -> Update.error_locked conf) in
|
||||||
|
let w_base =
|
||||||
|
let none conf =
|
||||||
|
if conf.bname = "" then output_error conf Def.Bad_Request
|
||||||
|
else output_error conf Def.Not_Found
|
||||||
|
in
|
||||||
|
w_base ~none
|
||||||
|
in
|
||||||
|
let w_person = w_person ~none:very_unknown in
|
||||||
|
fun conf ->
|
||||||
|
let bfile =
|
||||||
|
if conf.bname = "" then None
|
||||||
|
else
|
||||||
|
let bfile = Util.bpath (conf.bname ^ ".gwb") in
|
||||||
|
if Sys.file_exists bfile
|
||||||
|
then Some bfile
|
||||||
|
else None
|
||||||
|
in
|
||||||
|
let process () =
|
||||||
|
if conf.wizard
|
||||||
|
|| conf.friend
|
||||||
|
|| List.assoc_opt "visitor_access" conf.base_env <> Some "no"
|
||||||
|
then begin
|
||||||
|
#ifdef UNIX
|
||||||
|
begin match bfile with
|
||||||
|
| None -> ()
|
||||||
|
| Some bfile ->
|
||||||
|
let stat = Unix.stat bfile in
|
||||||
|
Unix.setgid stat.Unix.st_gid ;
|
||||||
|
Unix.setuid stat.Unix.st_uid ;
|
||||||
|
end ;
|
||||||
|
#endif
|
||||||
|
let plugins =
|
||||||
|
match List.assoc_opt "plugins" conf.Config.base_env with
|
||||||
|
| None -> []
|
||||||
|
| Some list -> String.split_on_char ',' list
|
||||||
|
in
|
||||||
|
if List.mem "*" plugins then
|
||||||
|
List.iter (fun (_ , fn) -> fn conf bfile) !GwdPlugin.se
|
||||||
|
else
|
||||||
|
List.iter (fun (ns, fn) -> if List.mem ns plugins then fn conf bfile) !GwdPlugin.se ;
|
||||||
|
let m = Option.value ~default:"" (p_getenv conf.env "m") in
|
||||||
|
if not @@ try_plugin plugins conf bfile m
|
||||||
|
then begin
|
||||||
|
if List.assoc_opt "counter" conf.base_env <> Some "no" &&
|
||||||
|
m <> "IM" && m <> "IM_C" && m <> "SRC" && m <> "DOC"
|
||||||
|
then begin
|
||||||
|
match
|
||||||
|
if only_special_env conf.env
|
||||||
|
then SrcfileDisplay.incr_welcome_counter conf
|
||||||
|
else SrcfileDisplay.incr_request_counter conf
|
||||||
|
with
|
||||||
|
| Some (welcome_cnt, request_cnt, start_date) ->
|
||||||
|
GwdLog.log begin fun oc ->
|
||||||
|
let thousand oc x = output_string oc @@ Mutil.string_of_int_sep "," x in
|
||||||
|
Printf.fprintf oc " #accesses %a (#welcome %a) since %s\n"
|
||||||
|
thousand (welcome_cnt + request_cnt) thousand welcome_cnt
|
||||||
|
start_date
|
||||||
|
end ;
|
||||||
|
| None -> ()
|
||||||
|
end ;
|
||||||
|
let incorrect_request ?(comment = "") conf _ =
|
||||||
|
incorrect_request ~comment:comment conf
|
||||||
|
in
|
||||||
|
let doc_aux conf base print =
|
||||||
|
match Util.p_getenv conf.env "s" with
|
||||||
|
| Some f ->
|
||||||
|
if Filename.check_suffix f ".txt" then
|
||||||
|
let f = Filename.chop_suffix f ".txt" in
|
||||||
|
SrcfileDisplay.print_source conf base f
|
||||||
|
else print conf f
|
||||||
|
| _ -> incorrect_request conf ~comment:"error #3" base
|
||||||
|
in
|
||||||
|
match m with
|
||||||
|
| "" ->
|
||||||
|
let base =
|
||||||
|
match bfile with
|
||||||
|
| None -> None
|
||||||
|
| Some bfile -> try Some (Gwdb.open_base bfile) with _ -> None
|
||||||
|
in
|
||||||
|
if base <> None then
|
||||||
|
w_base @@
|
||||||
|
if only_special_env conf.env then SrcfileDisplay.print_start
|
||||||
|
else w_person @@ fun conf base p ->
|
||||||
|
match p_getenv conf.env "ptempl" with
|
||||||
|
| Some t when List.assoc_opt "ptempl" conf.base_env = Some "yes" ->
|
||||||
|
Perso.interp_templ t conf base p
|
||||||
|
| _ -> person_selected conf base p
|
||||||
|
else if conf.bname = ""
|
||||||
|
then fun conf _ -> include_template conf [] "index" (fun () -> propose_base conf)
|
||||||
|
else
|
||||||
|
w_base begin (* print_start -> welcome.txt *)
|
||||||
|
if only_special_env conf.env then SrcfileDisplay.print_start
|
||||||
|
else w_person @@ fun conf base p ->
|
||||||
|
match p_getenv conf.env "ptempl" with
|
||||||
|
| Some t when List.assoc_opt "ptempl" conf.base_env = Some "yes" ->
|
||||||
|
Perso.interp_templ t conf base p
|
||||||
|
| _ -> person_selected conf base p
|
||||||
|
end
|
||||||
|
|
||||||
|
| "A" ->
|
||||||
|
AscendDisplay.print |> w_person |> w_base
|
||||||
|
| "ADD_FAM" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_add
|
||||||
|
| "ADD_FAM_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_add
|
||||||
|
| "ADD_IND" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateInd.print_add
|
||||||
|
| "ADD_IND_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateIndOk.print_add
|
||||||
|
| "ADD_PAR" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_add_parents
|
||||||
|
| "ADD_PAR_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_add_parents
|
||||||
|
| "ANM" ->
|
||||||
|
w_base @@ fun conf _ -> BirthdayDisplay.print_anniversaries conf
|
||||||
|
| "AN" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some x -> BirthdayDisplay.print_birth conf base (int_of_string x)
|
||||||
|
| _ -> BirthdayDisplay.print_menu_birth conf base
|
||||||
|
end
|
||||||
|
| "AD" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some x -> BirthdayDisplay.print_dead conf base (int_of_string x)
|
||||||
|
| _ -> BirthdayDisplay.print_menu_dead conf base
|
||||||
|
end
|
||||||
|
| "AM" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some x -> BirthdayDisplay.print_marriage conf base (int_of_string x)
|
||||||
|
| _ -> BirthdayDisplay.print_menu_marriage conf base
|
||||||
|
end
|
||||||
|
| "AS_OK" ->
|
||||||
|
w_base @@ AdvSearchOkDisplay.print
|
||||||
|
| "C" ->
|
||||||
|
w_base @@ w_person @@ CousinsDisplay.print
|
||||||
|
| "CAL" ->
|
||||||
|
fun conf _ -> Hutil.print_calendar conf
|
||||||
|
| "CHG_CHN" when conf.wizard ->
|
||||||
|
w_wizard @@ w_base @@ ChangeChildrenDisplay.print
|
||||||
|
| "CHG_CHN_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ChangeChildrenDisplay.print_ok
|
||||||
|
| "CHG_EVT_IND_ORD" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateInd.print_change_event_order
|
||||||
|
| "CHG_EVT_IND_ORD_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateIndOk.print_change_event_order
|
||||||
|
| "CHG_EVT_FAM_ORD" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_change_event_order
|
||||||
|
| "CHG_EVT_FAM_ORD_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_change_event_order
|
||||||
|
| "CHG_FAM_ORD" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_change_order
|
||||||
|
| "CHG_FAM_ORD_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_change_order_ok
|
||||||
|
| "CONN_WIZ" ->
|
||||||
|
w_wizard @@ w_base @@ WiznotesDisplay.connected_wizards
|
||||||
|
| "D" ->
|
||||||
|
w_base @@ w_person @@ DescendDisplay.print
|
||||||
|
| "DAG" ->
|
||||||
|
w_base @@ DagDisplay.print
|
||||||
|
| "DEL_FAM" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_del
|
||||||
|
| "DEL_FAM_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_del
|
||||||
|
|
||||||
|
| "DEL_IMAGE" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ImageCarrousel.print_del
|
||||||
|
| "DEL_IMAGE_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ImageCarrousel.print_del_ok
|
||||||
|
| "DEL_IMAGE_C_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ImageCarrousel.print_main_c
|
||||||
|
|
||||||
|
| "DEL_IND" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateInd.print_del
|
||||||
|
| "DEL_IND_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateIndOk.print_del
|
||||||
|
| "DOC" ->
|
||||||
|
w_base @@ fun conf base -> doc_aux conf base
|
||||||
|
ImageDisplay.print_source
|
||||||
|
| "DOCH" ->
|
||||||
|
w_base @@ fun conf base -> doc_aux conf base
|
||||||
|
(fun conf _base -> ImageDisplay.print_html conf)
|
||||||
|
| "F" ->
|
||||||
|
w_base @@ w_person @@ Perso.interp_templ "family"
|
||||||
|
| "H" ->
|
||||||
|
w_wizard @@ w_base @@ fun conf base ->
|
||||||
|
( match p_getenv conf.env "v" with
|
||||||
|
| Some f -> SrcfileDisplay.print conf base f
|
||||||
|
| None -> incorrect_request conf base ~comment:"error #4")
|
||||||
|
| "HIST" ->
|
||||||
|
w_base @@ History.print
|
||||||
|
| "HIST_CLEAN" ->
|
||||||
|
w_wizard @@ w_base @@ fun conf _ -> HistoryDiffDisplay.print_clean conf
|
||||||
|
| "HIST_CLEAN_OK" ->
|
||||||
|
w_wizard @@ w_base @@ fun conf _ -> HistoryDiffDisplay.print_clean_ok conf
|
||||||
|
| "HIST_DIFF" ->
|
||||||
|
w_base @@ HistoryDiffDisplay.print
|
||||||
|
| "HIST_SEARCH" ->
|
||||||
|
w_base @@ History.print_search
|
||||||
|
|
||||||
|
| "IM_C" ->
|
||||||
|
w_base @@ ImageCarrousel.print_c ~saved:false
|
||||||
|
| "IM_C_S" ->
|
||||||
|
w_base @@ ImageCarrousel.print_c ~saved:true
|
||||||
|
|
||||||
|
|
||||||
|
| "IM" ->
|
||||||
|
w_base @@ ImageDisplay.print
|
||||||
|
| "IMH" ->
|
||||||
|
w_base @@ fun conf _ -> ImageDisplay.print_html conf
|
||||||
|
| "INV_FAM" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_inv
|
||||||
|
| "INV_FAM_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_inv
|
||||||
|
| "KILL_ANC" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeIndDisplay.print_kill_ancestors
|
||||||
|
| "L" -> w_base @@ fun conf base -> Perso.interp_templ "list" conf base
|
||||||
|
(Gwdb.empty_person base Gwdb.dummy_iper)
|
||||||
|
| "LB" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_birth
|
||||||
|
| "LD" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_death
|
||||||
|
| "LINKED" ->
|
||||||
|
w_base @@ w_person @@ Perso.print_what_links
|
||||||
|
| "LL" ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_longest_lived
|
||||||
|
| "LM" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_marriage
|
||||||
|
| "MISC_NOTES" ->
|
||||||
|
w_base @@ NotesDisplay.print_misc_notes
|
||||||
|
| "MISC_NOTES_SEARCH" ->
|
||||||
|
w_base @@ NotesDisplay.print_misc_notes_search
|
||||||
|
| "MOD_DATA" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateDataDisplay.print_mod
|
||||||
|
| "MOD_DATA_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateDataDisplay.print_mod_ok
|
||||||
|
| "MOD_FAM" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateFam.print_mod
|
||||||
|
| "MOD_FAM_OK" when conf.wizard ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateFamOk.print_mod
|
||||||
|
| "MOD_IND" ->
|
||||||
|
w_wizard @@ w_base @@ UpdateInd.print_mod
|
||||||
|
| "MOD_IND_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ UpdateIndOk.print_mod
|
||||||
|
| "MOD_NOTES" ->
|
||||||
|
w_wizard @@ w_base @@ NotesDisplay.print_mod
|
||||||
|
| "MOD_NOTES_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ NotesDisplay.print_mod_ok
|
||||||
|
| "MOD_WIZNOTES" when conf.authorized_wizards_notes ->
|
||||||
|
w_base @@ WiznotesDisplay.print_mod
|
||||||
|
| "MOD_WIZNOTES_OK" when conf.authorized_wizards_notes ->
|
||||||
|
w_lock @@ w_base @@ WiznotesDisplay.print_mod_ok
|
||||||
|
| "MRG" ->
|
||||||
|
w_wizard @@ w_base @@ w_person @@ MergeDisplay.print
|
||||||
|
| "MRG_DUP" ->
|
||||||
|
w_wizard @@ w_base @@ MergeDupDisplay.main_page
|
||||||
|
| "MRG_DUP_IND_Y_N" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeDupDisplay.answ_ind_y_n
|
||||||
|
| "MRG_DUP_FAM_Y_N" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeDupDisplay.answ_fam_y_n
|
||||||
|
| "MRG_FAM" ->
|
||||||
|
w_wizard @@ w_base @@ MergeFamDisplay.print
|
||||||
|
| "MRG_FAM_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeFamOk.print_merge
|
||||||
|
| "MRG_MOD_FAM_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeFamOk.print_mod_merge
|
||||||
|
| "MRG_IND" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeIndDisplay.print
|
||||||
|
| "MRG_IND_OK" -> (* despite the _OK suffix, this one does not actually update databse *)
|
||||||
|
w_wizard @@ w_base @@ MergeIndOkDisplay.print_merge
|
||||||
|
| "MRG_MOD_IND_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ MergeIndOkDisplay.print_mod_merge
|
||||||
|
| "N" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some v -> Some.search_surname_print conf base Some.surname_not_found v
|
||||||
|
| _ -> AllnDisplay.print_surnames conf base
|
||||||
|
end
|
||||||
|
| "NG" -> w_base @@ begin fun conf base ->
|
||||||
|
(* Rétro-compatibilité <= 6.06 *)
|
||||||
|
let env =
|
||||||
|
match p_getenv conf.env "n" with
|
||||||
|
Some n ->
|
||||||
|
begin match p_getenv conf.env "t" with
|
||||||
|
Some "P" -> ("fn", Mutil.encode n) :: conf.env
|
||||||
|
| Some "N" -> ("sn", Mutil.encode n) :: conf.env
|
||||||
|
| _ -> ("v", Mutil.encode n) :: conf.env
|
||||||
|
end
|
||||||
|
| None -> conf.env
|
||||||
|
in
|
||||||
|
let conf = {conf with env = env} in
|
||||||
|
(* Nouveau mode de recherche. *)
|
||||||
|
match p_getenv conf.env "select" with
|
||||||
|
| Some "input" | None ->
|
||||||
|
(* Récupère le contenu non vide de la recherche. *)
|
||||||
|
let real_input label =
|
||||||
|
match p_getenv conf.env label with
|
||||||
|
| Some s -> if s = "" then None else Some s
|
||||||
|
| None -> None
|
||||||
|
in
|
||||||
|
(* Recherche par clé, sosa, alias ... *)
|
||||||
|
let search n =
|
||||||
|
let (pl, sosa_acc) = find_all conf base n in
|
||||||
|
match pl with
|
||||||
|
| [] ->
|
||||||
|
Some.search_surname_print conf base unknown n
|
||||||
|
| [p] ->
|
||||||
|
if sosa_acc
|
||||||
|
|| Gutil.person_of_string_key base n <> None
|
||||||
|
|| person_is_std_key conf base p n
|
||||||
|
then person_selected_with_redirect conf base p
|
||||||
|
else specify conf base n pl
|
||||||
|
| pl -> specify conf base n pl
|
||||||
|
in
|
||||||
|
begin match real_input "v" with
|
||||||
|
| Some n -> search n
|
||||||
|
| None ->
|
||||||
|
match real_input "fn", real_input "sn" with
|
||||||
|
Some fn, Some sn -> search (fn ^ " " ^ sn)
|
||||||
|
| Some fn, None ->
|
||||||
|
Some.search_first_name_print conf base fn
|
||||||
|
| None, Some sn ->
|
||||||
|
Some.search_surname_print conf base unknown sn
|
||||||
|
| None, None -> incorrect_request conf base ~comment:"error #5"
|
||||||
|
end
|
||||||
|
| Some i ->
|
||||||
|
relation_print conf base
|
||||||
|
(pget conf base (iper_of_string i))
|
||||||
|
end
|
||||||
|
| "NOTES" ->
|
||||||
|
w_base @@ NotesDisplay.print
|
||||||
|
| "OA" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_oldest_alive
|
||||||
|
| "OE" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_oldest_engagements
|
||||||
|
| "P" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some v -> Some.search_first_name_print conf base v
|
||||||
|
| None -> AllnDisplay.print_first_names conf base
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
| "PERSO" ->
|
||||||
|
w_base @@ w_person @@ Geneweb.Perso.interp_templ "perso"
|
||||||
|
|
||||||
|
| "POP_PYR" when conf.wizard || conf.friend ->
|
||||||
|
w_base @@ BirthDeathDisplay.print_population_pyramid
|
||||||
|
| "PS" ->
|
||||||
|
w_base @@ PlaceDisplay.print_all_places_surnames
|
||||||
|
| "PPS" ->
|
||||||
|
w_base @@ Place.print_all_places_surnames
|
||||||
|
| "R" ->
|
||||||
|
w_base @@ w_person @@ relation_print
|
||||||
|
| "REFRESH" ->
|
||||||
|
w_base @@ w_person @@ Perso.interp_templ "carrousel"
|
||||||
|
| "REQUEST" ->
|
||||||
|
w_wizard @@ fun _ _ ->
|
||||||
|
Output.status conf Def.OK;
|
||||||
|
Output.header conf "Content-type: text";
|
||||||
|
List.iter begin fun s ->
|
||||||
|
Output.print_sstring conf s ;
|
||||||
|
Output.print_sstring conf "\n"
|
||||||
|
end conf.Config.request ;
|
||||||
|
|
||||||
|
| "RESET_IMAGE_C_OK" ->
|
||||||
|
w_base @@ ImageCarrousel.print_main_c
|
||||||
|
|
||||||
|
| "RL" ->
|
||||||
|
w_base @@ RelationLink.print
|
||||||
|
| "RLM" ->
|
||||||
|
w_base @@ RelationDisplay.print_multi
|
||||||
|
| "S" ->
|
||||||
|
w_base @@ fun conf base -> SearchName.print conf base specify unknown
|
||||||
|
|
||||||
|
| "SND_IMAGE" -> w_wizard @@w_lock @@ w_base @@ ImageCarrousel.print
|
||||||
|
| "SND_IMAGE_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ImageCarrousel.print_send_ok
|
||||||
|
| "SND_IMAGE_C" ->
|
||||||
|
w_base @@ w_person @@ Perso.interp_templ "carrousel"
|
||||||
|
| "SND_IMAGE_C_OK" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ ImageCarrousel.print_main_c
|
||||||
|
|
||||||
|
| "SRC" ->
|
||||||
|
w_base @@ fun conf base -> begin match p_getenv conf.env "v" with
|
||||||
|
| Some f -> SrcfileDisplay.print_source conf base f
|
||||||
|
| _ -> incorrect_request conf base ~comment:"error #6"
|
||||||
|
end
|
||||||
|
| "STAT" ->
|
||||||
|
w_base @@ fun conf _ -> BirthDeathDisplay.print_statistics conf
|
||||||
|
| "CHANGE_WIZ_VIS" ->
|
||||||
|
w_wizard @@ w_lock @@ w_base @@ WiznotesDisplay.change_wizard_visibility
|
||||||
|
| "TP" ->
|
||||||
|
w_base @@ fun conf base ->
|
||||||
|
begin match Util.p_getenv conf.env "v" with
|
||||||
|
| Some f ->
|
||||||
|
begin match Util.find_person_in_env conf base "" with
|
||||||
|
| Some p -> Perso.interp_templ ("tp_" ^ f) conf base p
|
||||||
|
| _ -> Perso.interp_templ ("tp0_" ^ f) conf base
|
||||||
|
(Gwdb.empty_person base Gwdb.dummy_iper)
|
||||||
|
end
|
||||||
|
| None -> incorrect_request conf base ~comment:"error #7"
|
||||||
|
end
|
||||||
|
| "TT" ->
|
||||||
|
w_base @@ TitleDisplay.print
|
||||||
|
| "U" ->
|
||||||
|
w_wizard @@ w_base @@ w_person @@ updmenu_print
|
||||||
|
| "VIEW_WIZNOTES" when conf.authorized_wizards_notes ->
|
||||||
|
w_wizard @@ w_base @@ WiznotesDisplay.print_view
|
||||||
|
| "WIZNOTES" when conf.authorized_wizards_notes ->
|
||||||
|
w_base @@ WiznotesDisplay.print
|
||||||
|
| "WIZNOTES_SEARCH" when conf.authorized_wizards_notes ->
|
||||||
|
w_base @@ WiznotesDisplay.print_search
|
||||||
|
| _ ->
|
||||||
|
w_base @@ fun conf base ->
|
||||||
|
incorrect_request conf base ~comment:"error #10"
|
||||||
|
end conf bfile ;
|
||||||
|
end else begin
|
||||||
|
let title _ =
|
||||||
|
Printf.sprintf "%s %s %s"
|
||||||
|
(transl conf "base" |> Utf8.capitalize_fst)
|
||||||
|
conf.bname
|
||||||
|
(transl conf "reserved to friends or wizards")
|
||||||
|
|> Output.print_sstring conf
|
||||||
|
in
|
||||||
|
Hutil.rheader conf title ;
|
||||||
|
let base_name =
|
||||||
|
if conf.cgi then (Printf.sprintf "b=%s&" conf.bname) else ""
|
||||||
|
in
|
||||||
|
let user = transl_nth conf "user/password/cancel" 0 in
|
||||||
|
let passwd = transl_nth conf "user/password/cancel" 1 in
|
||||||
|
let body =
|
||||||
|
if conf.cgi then
|
||||||
|
Printf.sprintf {|
|
||||||
|
<input type="text" class="form-control" name="w"
|
||||||
|
title="%s/%s %s" placeholder="%s:%s"
|
||||||
|
aria-label="password input"
|
||||||
|
aria-describedby="username:password" autofocus>
|
||||||
|
<label for="w" class="sr-only">%s:%s</label>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button type="submit" class="btn btn-primary">OK</button>
|
||||||
|
</div>|}
|
||||||
|
(transl_nth conf "wizard/wizards/friend/friends/exterior" 2)
|
||||||
|
(transl_nth conf "wizard/wizards/friend/friends/exterior" 0)
|
||||||
|
passwd user passwd user passwd
|
||||||
|
else
|
||||||
|
Printf.sprintf {|
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li>%s%s <a href="%s?%sw=f"> %s</a></li>
|
||||||
|
<li>%s%s <a href="%s?%sw=w"> %s</a></li>
|
||||||
|
</ul>
|
||||||
|
</div> |}
|
||||||
|
(transl conf "access" |> Utf8.capitalize_fst) (transl conf ":")
|
||||||
|
(conf.command :> string) base_name
|
||||||
|
(transl_nth conf "wizard/wizards/friend/friends/exterior" 2)
|
||||||
|
(transl conf "access" |> Utf8.capitalize_fst) (transl conf ":")
|
||||||
|
(conf.command :> string) base_name
|
||||||
|
(transl_nth conf "wizard/wizards/friend/friends/exterior" 0)
|
||||||
|
in
|
||||||
|
Output.print_sstring conf
|
||||||
|
(Printf.sprintf {|
|
||||||
|
<form class="form-inline" method="post" action="%s">
|
||||||
|
<div class="input-group mt-1">
|
||||||
|
<input type="hidden" name="b" value="%s">
|
||||||
|
%s
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|} (conf.command :> string) (conf.bname) body
|
||||||
|
);
|
||||||
|
Hutil.trailer conf
|
||||||
|
end
|
||||||
|
in
|
||||||
|
if conf.debug then Mutil.bench (__FILE__ ^ " " ^ string_of_int __LINE__) process
|
||||||
|
else process ()
|
||||||
|
|
||||||
|
let treat_request conf =
|
||||||
|
try treat_request conf with Update.ModErr _ -> Output.flush conf
|
59
bin/gwd/request.mli
Normal file
59
bin/gwd/request.mli
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
open Geneweb
|
||||||
|
|
||||||
|
val make_senv : Config.config -> Gwdb.base -> Config.config
|
||||||
|
val make_henv : Config.config -> Gwdb.base -> Config.config
|
||||||
|
|
||||||
|
val w_base :
|
||||||
|
none:(Config.config -> 'a) ->
|
||||||
|
(Config.config -> Gwdb.base -> 'a) ->
|
||||||
|
Config.config ->
|
||||||
|
string option ->
|
||||||
|
'a
|
||||||
|
(** [w_lock ~none callback conf base]
|
||||||
|
Acquire a write lock on the base and call [callback], or fail with [none].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val w_lock :
|
||||||
|
onerror:(Config.config -> string option -> 'a) ->
|
||||||
|
(Config.config -> string option -> 'a) ->
|
||||||
|
Config.config ->
|
||||||
|
string option ->
|
||||||
|
'a
|
||||||
|
(** [w_lock ~onerror callback conf base]
|
||||||
|
Acquire a write lock on the base and call the callback, or fail with [onerror].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val w_wizard :
|
||||||
|
(Config.config -> Gwdb.base -> unit) -> Config.config -> Gwdb.base -> unit
|
||||||
|
(** [w_wizard callback conf base]
|
||||||
|
Run [callback conf base] if conf has wizard rights or
|
||||||
|
return [Forbidden] or [Unauthorized].
|
||||||
|
*)
|
||||||
|
|
||||||
|
val w_person :
|
||||||
|
none:(Config.config -> Gwdb.base -> 'a) ->
|
||||||
|
(Config.config -> Gwdb.base -> Gwdb.person -> 'a) ->
|
||||||
|
Config.config ->
|
||||||
|
Gwdb.base ->
|
||||||
|
'a
|
||||||
|
(** [w_person ~none callback conf base]
|
||||||
|
Find a person in environement and call [callback], or fail with [none].
|
||||||
|
*)
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
(* Used internally by [gwd]. Not intended to be used by other programs. *)
|
||||||
|
val treat_request : Config.config -> unit
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
(* Used by v7 plugin *)
|
||||||
|
val incorrect_request : ?comment:string -> Config.config -> unit
|
||||||
|
val very_unknown : Config.config -> Gwdb.base -> unit
|
||||||
|
val only_special_env : (string * _) list -> bool
|
||||||
|
|
||||||
|
(**/**)
|
206
bin/gwd/robot.ml
Normal file
206
bin/gwd/robot.ml
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
(* Copyright (c) 1998-2007 INRIA *)
|
||||||
|
|
||||||
|
open Geneweb
|
||||||
|
open Config
|
||||||
|
|
||||||
|
let magic_robot = "GWRB0007"
|
||||||
|
|
||||||
|
module W = Map.Make (struct
|
||||||
|
type t = string
|
||||||
|
|
||||||
|
let compare = compare
|
||||||
|
end)
|
||||||
|
|
||||||
|
type norfriwiz = Normal | Friend of string | Wizard of string
|
||||||
|
|
||||||
|
type who = {
|
||||||
|
acc_times : float list;
|
||||||
|
oldest_time : float;
|
||||||
|
nb_connect : int;
|
||||||
|
nbase : string;
|
||||||
|
utype : norfriwiz;
|
||||||
|
}
|
||||||
|
|
||||||
|
type excl = {
|
||||||
|
mutable excl : (string * int ref) list;
|
||||||
|
mutable who : who W.t;
|
||||||
|
mutable max_conn : int * string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let robot_error conf cnt sec =
|
||||||
|
Output.status conf Def.Forbidden;
|
||||||
|
Output.header conf "Content-type: text/html; charset=iso-8859-1";
|
||||||
|
let env =
|
||||||
|
[
|
||||||
|
("cnt", Adef.encoded (string_of_int cnt));
|
||||||
|
("sec", Adef.encoded (string_of_int sec));
|
||||||
|
]
|
||||||
|
in
|
||||||
|
Util.include_template conf env "robot" (fun () ->
|
||||||
|
let title _ = Output.print_sstring conf "Access refused" in
|
||||||
|
Output.print_sstring conf "<head><title>";
|
||||||
|
title true;
|
||||||
|
Output.print_sstring conf "</title>\n<body>\n<h1>";
|
||||||
|
title false;
|
||||||
|
Output.print_sstring conf "</body>\n");
|
||||||
|
raise Exit
|
||||||
|
|
||||||
|
let purge_who tm xcl sec =
|
||||||
|
let sec = float sec in
|
||||||
|
let to_remove =
|
||||||
|
W.fold
|
||||||
|
(fun k who l ->
|
||||||
|
match who.acc_times with
|
||||||
|
| tm0 :: _ -> if tm -. tm0 > sec then k :: l else l
|
||||||
|
| [] -> k :: l)
|
||||||
|
xcl.who []
|
||||||
|
in
|
||||||
|
List.iter (fun k -> xcl.who <- W.remove k xcl.who) to_remove
|
||||||
|
|
||||||
|
let input_excl ic =
|
||||||
|
let b = really_input_string ic (String.length magic_robot) in
|
||||||
|
if b <> magic_robot then raise Not_found else (input_value ic : excl)
|
||||||
|
|
||||||
|
let output_excl oc xcl =
|
||||||
|
output_string oc magic_robot;
|
||||||
|
output_value oc (xcl : excl)
|
||||||
|
|
||||||
|
let robot_excl () =
|
||||||
|
let fname = SrcfileDisplay.adm_file "robot" in
|
||||||
|
let xcl =
|
||||||
|
match try Some (Secure.open_in_bin fname) with _ -> None with
|
||||||
|
| Some ic ->
|
||||||
|
let v =
|
||||||
|
try input_excl ic
|
||||||
|
with _ -> { excl = []; who = W.empty; max_conn = (0, "") }
|
||||||
|
in
|
||||||
|
close_in ic;
|
||||||
|
v
|
||||||
|
| None -> { excl = []; who = W.empty; max_conn = (0, "") }
|
||||||
|
in
|
||||||
|
(xcl, fname)
|
||||||
|
|
||||||
|
let min_disp_req = ref 6
|
||||||
|
|
||||||
|
let check tm from max_call sec conf suicide =
|
||||||
|
let nfw =
|
||||||
|
if conf.wizard then Wizard conf.user
|
||||||
|
else if conf.friend then Friend conf.user
|
||||||
|
else Normal
|
||||||
|
in
|
||||||
|
let xcl, fname = robot_excl () in
|
||||||
|
let refused =
|
||||||
|
match try Some (List.assoc from xcl.excl) with Not_found -> None with
|
||||||
|
| Some att ->
|
||||||
|
incr att;
|
||||||
|
if !att mod max_call = 0 then
|
||||||
|
Gwd_lib.GwdLog.syslog `LOG_NOTICE
|
||||||
|
@@ Printf.sprintf
|
||||||
|
{|From: %s --- %d refused attempts --- to restore access, delete file "%s"|}
|
||||||
|
from !att fname;
|
||||||
|
true
|
||||||
|
| None ->
|
||||||
|
purge_who tm xcl sec;
|
||||||
|
let r = try (W.find from xcl.who).acc_times with Not_found -> [] in
|
||||||
|
let cnt, tml, tm0 =
|
||||||
|
let sec = float sec in
|
||||||
|
let rec count cnt tml = function
|
||||||
|
| [] -> (cnt, tml, tm)
|
||||||
|
| [ tm1 ] ->
|
||||||
|
if tm -. tm1 < sec then (cnt + 1, tm1 :: tml, tm1)
|
||||||
|
else (cnt, tml, tm1)
|
||||||
|
| tm1 :: tml1 ->
|
||||||
|
if tm -. tm1 < sec then count (cnt + 1) (tm1 :: tml) tml1
|
||||||
|
else (cnt, tml, tm1)
|
||||||
|
in
|
||||||
|
count 1 [] r
|
||||||
|
in
|
||||||
|
let r = List.rev tml in
|
||||||
|
xcl.who <-
|
||||||
|
W.add from
|
||||||
|
{
|
||||||
|
acc_times = tm :: r;
|
||||||
|
oldest_time = tm0;
|
||||||
|
nb_connect = cnt;
|
||||||
|
nbase = conf.bname;
|
||||||
|
utype = nfw;
|
||||||
|
}
|
||||||
|
xcl.who;
|
||||||
|
let refused =
|
||||||
|
if suicide || cnt > max_call then (
|
||||||
|
Gwd_lib.GwdLog.log (fun oc ->
|
||||||
|
Printf.fprintf oc "--- %s is a robot" from;
|
||||||
|
if suicide then
|
||||||
|
Printf.fprintf oc " (called the \"suicide\" request)\n"
|
||||||
|
else
|
||||||
|
Printf.fprintf oc
|
||||||
|
" (%d > %d connections in %g <= %d seconds)\n" cnt max_call
|
||||||
|
(tm -. tm0) sec);
|
||||||
|
xcl.excl <- (from, ref 1) :: xcl.excl;
|
||||||
|
xcl.who <- W.remove from xcl.who;
|
||||||
|
xcl.max_conn <- (0, "");
|
||||||
|
true)
|
||||||
|
else false
|
||||||
|
in
|
||||||
|
(match xcl.excl with
|
||||||
|
| [ _; _ ] ->
|
||||||
|
Gwd_lib.GwdLog.log (fun oc ->
|
||||||
|
List.iter
|
||||||
|
(fun (s, att) ->
|
||||||
|
Printf.fprintf oc "--- excluded:";
|
||||||
|
Printf.fprintf oc " %s (%d refused attempts)\n" s !att)
|
||||||
|
xcl.excl;
|
||||||
|
Printf.fprintf oc "--- to restore access, delete file \"%s\"\n"
|
||||||
|
fname)
|
||||||
|
| _ -> ());
|
||||||
|
let list, nconn =
|
||||||
|
W.fold
|
||||||
|
(fun k w (list, nconn) ->
|
||||||
|
let tm = w.oldest_time in
|
||||||
|
let nb = w.nb_connect in
|
||||||
|
if nb > fst xcl.max_conn then xcl.max_conn <- (nb, k);
|
||||||
|
( (if nb < !min_disp_req then list else (k, tm, nb) :: list),
|
||||||
|
nconn + 1 ))
|
||||||
|
xcl.who ([], 0)
|
||||||
|
in
|
||||||
|
let list =
|
||||||
|
List.sort
|
||||||
|
(fun (_, tm1, nb1) (_, tm2, nb2) ->
|
||||||
|
match compare nb2 nb1 with 0 -> compare tm2 tm1 | x -> x)
|
||||||
|
list
|
||||||
|
in
|
||||||
|
Gwd_lib.GwdLog.log (fun oc ->
|
||||||
|
List.iter
|
||||||
|
(fun (k, tm0, nb) ->
|
||||||
|
Printf.fprintf oc "--- %3d req - %3.0f sec - %s\n" nb
|
||||||
|
(tm -. tm0) k)
|
||||||
|
list;
|
||||||
|
Printf.fprintf oc "--- max %d req by %s / conn %d\n"
|
||||||
|
(fst xcl.max_conn) (snd xcl.max_conn) nconn);
|
||||||
|
refused
|
||||||
|
in
|
||||||
|
(match try Some (Secure.open_out_bin fname) with Sys_error _ -> None with
|
||||||
|
| Some oc ->
|
||||||
|
output_excl oc xcl;
|
||||||
|
close_out oc
|
||||||
|
| None -> ());
|
||||||
|
if refused then robot_error conf max_call sec;
|
||||||
|
W.fold
|
||||||
|
(fun _ w (c, cw, cf, wl) ->
|
||||||
|
if w.nbase = conf.bname && w.nbase <> "" then
|
||||||
|
match w.utype with
|
||||||
|
| Wizard n ->
|
||||||
|
let at = List.hd w.acc_times in
|
||||||
|
if List.mem_assoc n wl then
|
||||||
|
let old_at = List.assoc n wl in
|
||||||
|
if at > old_at then
|
||||||
|
let wl = List.remove_assoc n wl in
|
||||||
|
(c, cw, cf, (n, at) :: wl)
|
||||||
|
else (c, cw, cf, wl)
|
||||||
|
else (c + 1, cw + 1, cf, (n, at) :: wl)
|
||||||
|
| Friend _ ->
|
||||||
|
if w.nb_connect > 2 then (c + 1, cw, cf + 1, wl) else (c, cw, cf, wl)
|
||||||
|
| Normal ->
|
||||||
|
if w.nb_connect > 2 then (c + 1, cw, cf, wl) else (c, cw, cf, wl)
|
||||||
|
else (c, cw, cf, wl))
|
||||||
|
xcl.who (0, 0, 0, [])
|
53
bin/gwd/robot.mli
Normal file
53
bin/gwd/robot.mli
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
(** A module handling robots requests *)
|
||||||
|
(* S: This module seems obsolete *)
|
||||||
|
|
||||||
|
val magic_robot : string
|
||||||
|
|
||||||
|
module W : Map.S with type key = string
|
||||||
|
|
||||||
|
type norfriwiz = Normal | Friend of string | Wizard of string
|
||||||
|
|
||||||
|
type who = private {
|
||||||
|
acc_times : float list; (** The timings of the connexion attempts *)
|
||||||
|
oldest_time : float;
|
||||||
|
(** The first connection in the specified window
|
||||||
|
(check option -robot-xcl) of time in which successive
|
||||||
|
connections are attempted. *)
|
||||||
|
nb_connect : int; (** The number of connection in the specified window. *)
|
||||||
|
nbase : string; (** Always be equal to conf.bname *)
|
||||||
|
utype : norfriwiz; (** The kind of robot *)
|
||||||
|
}
|
||||||
|
|
||||||
|
type excl = {
|
||||||
|
mutable excl : (string * int ref) list;
|
||||||
|
mutable who : who W.t;
|
||||||
|
mutable max_conn : int * string;
|
||||||
|
}
|
||||||
|
(** A collection of robots: the list contains forbidden robots and
|
||||||
|
the map contains accepted (under conditions) robots. *)
|
||||||
|
|
||||||
|
val robot_error : Geneweb.Config.config -> int -> int -> 'a
|
||||||
|
(** Prints an error "Access refuned" in HTML and raises an `Exit` exception. *)
|
||||||
|
|
||||||
|
val robot_excl : unit -> excl * string
|
||||||
|
(** Reads the content of the admin file managing robots and returns its content
|
||||||
|
and the full file name. *)
|
||||||
|
|
||||||
|
val min_disp_req : int ref
|
||||||
|
|
||||||
|
val check :
|
||||||
|
float ->
|
||||||
|
string ->
|
||||||
|
int ->
|
||||||
|
int ->
|
||||||
|
Geneweb.Config.config ->
|
||||||
|
bool ->
|
||||||
|
int * int * int * (string * float) list
|
||||||
|
(** [check tm from max_call sec conf suicide]
|
||||||
|
Returns a tuple containing:
|
||||||
|
* the number of robots who attempted to connect twice
|
||||||
|
* the number of wizard robots who attempted to connect twice
|
||||||
|
* the number of friend robots who attempted to connect twice
|
||||||
|
* the wizards list and their last connection attempt.
|
||||||
|
It also updates the robot file by blocking robots who did too many attempts.
|
||||||
|
*)
|
51
bin/gwdiff/README
Normal file
51
bin/gwdiff/README
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
OVERVIEW:
|
||||||
|
|
||||||
|
gwdiff will help you to target differences between two GeneWeb databases. So
|
||||||
|
far it needs your help to know what to compare. Two modes are available:
|
||||||
|
|
||||||
|
- descendants checks (option -d): it will compare the descendants of the
|
||||||
|
person you have found in both databases (Spouses and their parents are
|
||||||
|
compared too)
|
||||||
|
|
||||||
|
- descendants of all ascendants (option -ad): it will found ascendants of the
|
||||||
|
person you have found in both databases that are available in both data
|
||||||
|
bases. For each top person identified, it will compare its descendants in
|
||||||
|
both databases.
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
|
||||||
|
Your cousin has just sent you a new GEDCOM file, import it to GeneWeb (data
|
||||||
|
base b1). You want to update your database (b2) according to b1 database.
|
||||||
|
Now, find a person defined in both databases (ex.: Jean DUPONT). In base b1,
|
||||||
|
it is "Jean.0 DUPONT"; in base b2, it is "Jean.3 DUPONT". Run the following
|
||||||
|
command:
|
||||||
|
|
||||||
|
gwdiff -d -1 Jean 0 DUPONT -2 Jean 3 DUPONT b1 b2
|
||||||
|
|
||||||
|
If your are interested in the descendants of its ascendants, you can try:
|
||||||
|
|
||||||
|
gwdiff -ad -1 Jean 0 DUPONT -2 Jean 3 DUPONT b1 b2
|
||||||
|
|
||||||
|
So far, the checks include:
|
||||||
|
- first name: value from b1 has to be found in b2 (first name or first name
|
||||||
|
aliases)
|
||||||
|
- surname: value from b1 has to be found in b2 (surname or surname aliases)
|
||||||
|
- birth date
|
||||||
|
- birth place: if it is set in b1, it has to be set in b2 (whatever the value)
|
||||||
|
- death status
|
||||||
|
- death date
|
||||||
|
- death place: if it is set in b1, it has to be set in b2 (whatever the value)
|
||||||
|
- occupation: if it is set in b1, it has to be set in b2 (whatever the value)
|
||||||
|
- marriage date
|
||||||
|
- marriage place: if it is set in b1, it has to be set in b2 (whatever the
|
||||||
|
value)
|
||||||
|
- divorce date
|
||||||
|
- spouses
|
||||||
|
- parents of spouses
|
||||||
|
- children
|
||||||
|
|
||||||
|
BUG REPORTS AND USER FEEDBACK:
|
||||||
|
|
||||||
|
Send your bug reports by E-mail to:
|
||||||
|
|
||||||
|
Ludovic LEDIEU: lledieu@free.fr
|
6
bin/gwdiff/dune.in
Normal file
6
bin/gwdiff/dune.in
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(executables
|
||||||
|
(names gwdiff)
|
||||||
|
(public_names geneweb.gwdiff)
|
||||||
|
(modules gwdiff)
|
||||||
|
(libraries unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
652
bin/gwdiff/gwdiff.ml
Normal file
652
bin/gwdiff/gwdiff.ml
Normal file
@ -0,0 +1,652 @@
|
|||||||
|
(* Copyright (c) 2001 Ludovic LEDIEU *)
|
||||||
|
|
||||||
|
open Def
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
(*= TODO =====================================================================
|
||||||
|
- Improve the way not to check several time the same persons.
|
||||||
|
=========================================================================== *)
|
||||||
|
|
||||||
|
let in_file1 = ref ""
|
||||||
|
let in_file2 = ref ""
|
||||||
|
let html = ref false
|
||||||
|
let root = ref ""
|
||||||
|
let cr = ref ""
|
||||||
|
|
||||||
|
(** Messages are printed when there is a difference between a person
|
||||||
|
present in the two bases explored. *)
|
||||||
|
type messages =
|
||||||
|
| MsgBadChild of iper
|
||||||
|
| MsgBirthDate
|
||||||
|
| MsgBirthPlace
|
||||||
|
| MsgChildMissing of iper
|
||||||
|
| MsgChildren of iper
|
||||||
|
| MsgDeathDate
|
||||||
|
| MsgDeathPlace
|
||||||
|
| MsgDivorce
|
||||||
|
| MsgFirstName
|
||||||
|
| MsgOccupation
|
||||||
|
| MsgParentsMissing
|
||||||
|
| MsgMarriageDate
|
||||||
|
| MsgMarriagePlace
|
||||||
|
| MsgSex
|
||||||
|
| MsgSpouseMissing of iper
|
||||||
|
| MsgSpouses of iper
|
||||||
|
| MsgSurname
|
||||||
|
|
||||||
|
(** [person_string base iper]
|
||||||
|
Returns the string associated to the person with id `iper` in the base
|
||||||
|
`base`. *)
|
||||||
|
let person_string base iper =
|
||||||
|
let p = poi base iper in
|
||||||
|
let fn = sou base (get_first_name p) in
|
||||||
|
let sn = sou base (get_surname p) in
|
||||||
|
if sn = "?" || fn = "?" then fn ^ " " ^ sn ^ " (#" ^ string_of_iper iper ^ ")"
|
||||||
|
else fn ^ "." ^ string_of_int (get_occ p) ^ " " ^ sn
|
||||||
|
|
||||||
|
(** Returns the string associated to a person in HTML if the html option is set,
|
||||||
|
otherwise it has the same effect tja, `person_string`. *)
|
||||||
|
let person_link bname base iper target =
|
||||||
|
if !html then
|
||||||
|
Printf.sprintf "<A HREF=\"%s%s_w?i=%s\" TARGET=\"%s\">%s</A>" !root bname
|
||||||
|
(string_of_iper iper) target (person_string base iper)
|
||||||
|
else person_string base iper
|
||||||
|
|
||||||
|
(** Prints a message *)
|
||||||
|
let print_message base1 msg =
|
||||||
|
Printf.printf " ";
|
||||||
|
(match msg with
|
||||||
|
| MsgBadChild iper1 ->
|
||||||
|
Printf.printf "can not isolate one child match: %s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
| MsgBirthDate -> Printf.printf "birth date"
|
||||||
|
| MsgBirthPlace -> Printf.printf "birth place"
|
||||||
|
| MsgChildMissing iper1 ->
|
||||||
|
Printf.printf "child missing: %s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
| MsgChildren iper1 ->
|
||||||
|
Printf.printf "more than one child match: %s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
| MsgDeathDate -> Printf.printf "death (status or date)"
|
||||||
|
| MsgDeathPlace -> Printf.printf "death place"
|
||||||
|
| MsgDivorce -> Printf.printf "divorce"
|
||||||
|
| MsgFirstName -> Printf.printf "first name"
|
||||||
|
| MsgOccupation -> Printf.printf "occupation"
|
||||||
|
| MsgParentsMissing -> Printf.printf "parents missing"
|
||||||
|
| MsgMarriageDate -> Printf.printf "marriage date"
|
||||||
|
| MsgMarriagePlace -> Printf.printf "marriage place"
|
||||||
|
| MsgSex -> Printf.printf "sex"
|
||||||
|
| MsgSpouseMissing iper1 ->
|
||||||
|
Printf.printf "spouse missing: %s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
| MsgSpouses iper1 ->
|
||||||
|
Printf.printf "more than one spouse match: %s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
| MsgSurname -> Printf.printf "surname");
|
||||||
|
Printf.printf "%s" !cr
|
||||||
|
|
||||||
|
(** Prints messages associates to the two families identifiers in argument *)
|
||||||
|
let print_f_messages base1 base2 ifam1 ifam2 res =
|
||||||
|
let f1 = foi base1 ifam1 in
|
||||||
|
let f2 = foi base2 ifam2 in
|
||||||
|
Printf.printf "%s x %s%s/ %s x %s%s"
|
||||||
|
(person_link !in_file1 base1 (get_father f1) "base1")
|
||||||
|
(person_link !in_file1 base1 (get_mother f1) "base1")
|
||||||
|
!cr
|
||||||
|
(person_link !in_file2 base2 (get_father f2) "base2")
|
||||||
|
(person_link !in_file2 base2 (get_father f2) "base2")
|
||||||
|
!cr;
|
||||||
|
List.iter (print_message base1) res
|
||||||
|
|
||||||
|
(** Same, but for persons *)
|
||||||
|
let print_p_messages base1 base2 iper1 iper2 res =
|
||||||
|
Printf.printf "%s / %s%s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
(person_link !in_file2 base2 iper2 "base2")
|
||||||
|
!cr;
|
||||||
|
List.iter (print_message base1) res
|
||||||
|
|
||||||
|
(** [compatible_names src_name dest_name_list]
|
||||||
|
Returns true if `src_name` is in `dest_name_list` (case insensitive) *)
|
||||||
|
let compatible_names src_name dest_name_list =
|
||||||
|
let src_name = Name.lower src_name in
|
||||||
|
let dest_name_list = List.map Name.lower dest_name_list in
|
||||||
|
List.mem src_name dest_name_list
|
||||||
|
|
||||||
|
(** [compatible_str_field istr1 istr2]
|
||||||
|
Checks the compatibility of two string identifiers, i.e.
|
||||||
|
if istr1 is not the empty string identifier, then istr2
|
||||||
|
must not be. *)
|
||||||
|
let compatible_str_field istr1 istr2 =
|
||||||
|
is_empty_string istr1 || not (is_empty_string istr2)
|
||||||
|
|
||||||
|
(** Returns a list of intervals of SDN (SDN 1 is November 25, 4714 BC Gregorian
|
||||||
|
calendar) of the date in argument. An interval has the format (b, b'),
|
||||||
|
where b is an optional lower bound (None => no bound), and b' an optional
|
||||||
|
upper bound. *)
|
||||||
|
let dmy_to_sdn_range_l dmy =
|
||||||
|
let sdn_of_dmy dmy =
|
||||||
|
let sdn = Calendar.sdn_of_gregorian dmy in
|
||||||
|
let sdn = if dmy.month = 0 || dmy.day = 0 then sdn + 1 else sdn in
|
||||||
|
let sdn2 =
|
||||||
|
if dmy.delta != 0 then sdn + dmy.delta
|
||||||
|
else
|
||||||
|
let dmy2 =
|
||||||
|
{
|
||||||
|
year =
|
||||||
|
(if dmy.month = 0 || (dmy.month = 12 && dmy.day = 0) then
|
||||||
|
dmy.year + 1
|
||||||
|
else dmy.year);
|
||||||
|
month =
|
||||||
|
(if dmy.month = 0 then 1
|
||||||
|
else if dmy.day = 0 then
|
||||||
|
if dmy.month = 12 then 1 else dmy.month + 1
|
||||||
|
else dmy.month);
|
||||||
|
day = (if dmy.day = 0 then 1 else dmy.day);
|
||||||
|
prec = (if dmy.month = 0 || dmy.day = 0 then Before else Sure);
|
||||||
|
delta = dmy.delta;
|
||||||
|
}
|
||||||
|
in
|
||||||
|
let sdn2 = Calendar.sdn_of_gregorian dmy2 in
|
||||||
|
if dmy2.prec = Before then sdn2 - 1 else sdn2
|
||||||
|
in
|
||||||
|
(sdn, sdn2)
|
||||||
|
in
|
||||||
|
(* S: calls to sdn_of_dmy dmy can be factorized *)
|
||||||
|
match dmy.prec with
|
||||||
|
| Sure ->
|
||||||
|
let sdn1, sdn2 = sdn_of_dmy dmy in
|
||||||
|
[ (Some sdn1, Some sdn2) ]
|
||||||
|
| Maybe ->
|
||||||
|
let sdn1, sdn2 = sdn_of_dmy dmy in
|
||||||
|
[ (Some sdn1, Some sdn2); (None, None) ]
|
||||||
|
| About ->
|
||||||
|
let sdn1, sdn2 = sdn_of_dmy dmy in
|
||||||
|
let delta = (sdn2 - sdn1 + 1) * 5 in
|
||||||
|
[ (Some (sdn1 - delta), Some (sdn2 + delta)) ]
|
||||||
|
| Before ->
|
||||||
|
let _sdn1, sdn2 = sdn_of_dmy dmy in
|
||||||
|
[ (None, Some sdn2) ]
|
||||||
|
| After ->
|
||||||
|
let sdn1, _sdn2 = sdn_of_dmy dmy in
|
||||||
|
[ (Some sdn1, None) ]
|
||||||
|
| OrYear dmy2 ->
|
||||||
|
let sdn11, sdn12 = sdn_of_dmy dmy in
|
||||||
|
let sdn21, sdn22 = sdn_of_dmy (Date.dmy_of_dmy2 dmy2) in
|
||||||
|
[ (Some sdn11, Some sdn12); (Some sdn21, Some sdn22) ]
|
||||||
|
| YearInt dmy2 ->
|
||||||
|
let sdn11, _sdn12 = sdn_of_dmy dmy in
|
||||||
|
let _sdn21, sdn22 = sdn_of_dmy (Date.dmy_of_dmy2 dmy2) in
|
||||||
|
[ (Some sdn11, Some sdn22) ]
|
||||||
|
|
||||||
|
(** [compatible_sdn i1 i2]
|
||||||
|
Checks if two intervals `i1` and `i2` (as described for `dmy_to_sdn_range_l`)
|
||||||
|
are compatible, i.e. if i2 is a sub interval of i1. *)
|
||||||
|
let compatible_sdn (sdn11, sdn12) (sdn21, sdn22) =
|
||||||
|
if (sdn21, sdn22) = (None, None) then true
|
||||||
|
else
|
||||||
|
(* S: Add unit argument to bool2 to make good use of OCaml laziness *)
|
||||||
|
let bool1 =
|
||||||
|
match (sdn11, sdn21) with
|
||||||
|
| Some sdn1, Some sdn2 -> sdn1 <= sdn2
|
||||||
|
| None, _ -> true
|
||||||
|
| Some _, None -> false
|
||||||
|
in
|
||||||
|
let bool2 =
|
||||||
|
match (sdn12, sdn22) with
|
||||||
|
| Some sdn1, Some sdn2 -> sdn1 >= sdn2
|
||||||
|
| None, _ -> true
|
||||||
|
| Some _, None -> false
|
||||||
|
in
|
||||||
|
bool1 && bool2
|
||||||
|
|
||||||
|
(** [compatible_sdn_l l i]
|
||||||
|
Checks if there exists an interval in `l` that is compatible with `i` *)
|
||||||
|
let compatible_sdn_l sdn1_l sdn2 =
|
||||||
|
(* S: replace by List.exists *)
|
||||||
|
List.fold_left (fun r sdn1 -> r || compatible_sdn sdn1 sdn2) false sdn1_l
|
||||||
|
|
||||||
|
(** [compatible_sdn_l l1 l2]
|
||||||
|
Checks if for all intervals `i2` in `l2`, there exists an interval `i1` in
|
||||||
|
`l1` such that `i1` is compatible with `i2` *)
|
||||||
|
let compatible_sdn_ll sdn1_l sdn2_l =
|
||||||
|
List.fold_left (fun r sdn2 -> r && compatible_sdn_l sdn1_l sdn2) true sdn2_l
|
||||||
|
|
||||||
|
(** [compatible_dmys d1 d2]
|
||||||
|
Checks if `d1` is compatible with `d2`, i.e. if despite a potential lack
|
||||||
|
of precision in the dates, d2 is more precise than d1. *)
|
||||||
|
let compatible_dmys dmy1 dmy2 =
|
||||||
|
compatible_sdn_ll (dmy_to_sdn_range_l dmy1) (dmy_to_sdn_range_l dmy2)
|
||||||
|
|
||||||
|
(** [compatible_dates date1 date2]
|
||||||
|
Same than before, but also checks the kind of date (Dgreg or Dtext)
|
||||||
|
and, in the first case, if calendars are compatible. *)
|
||||||
|
let compatible_dates date1 date2 =
|
||||||
|
let compatible_cals cal1 cal2 =
|
||||||
|
match (cal1, cal2) with
|
||||||
|
| Dgregorian, Djulian | Dgregorian, Dfrench -> true
|
||||||
|
| _ -> cal1 = cal2
|
||||||
|
in
|
||||||
|
if date1 = date2 then true
|
||||||
|
else
|
||||||
|
match (date1, date2) with
|
||||||
|
| Dgreg (dmy1, cal1), Dgreg (dmy2, cal2) ->
|
||||||
|
compatible_dmys dmy1 dmy2 && compatible_cals cal1 cal2
|
||||||
|
| Dgreg (_, _), Dtext _ -> false
|
||||||
|
| Dtext _, _ -> true
|
||||||
|
|
||||||
|
(** Same than before, but for Adef.ctype. *)
|
||||||
|
let compatible_cdates cdate1 cdate2 =
|
||||||
|
let od1 = Date.od_of_cdate cdate1 in
|
||||||
|
let od2 = Date.od_of_cdate cdate2 in
|
||||||
|
match (od1, od2) with
|
||||||
|
| Some date1, Some date2 -> compatible_dates date1 date2
|
||||||
|
| Some _, None -> false
|
||||||
|
| None, _ -> true
|
||||||
|
|
||||||
|
(** Checks if birth between two persons are compatible, i.e. if their birth date
|
||||||
|
(baptism date if birth date not provided) and place are compatible, and
|
||||||
|
returns a list of messages.
|
||||||
|
If birth is not provided, checks bathism date instead.
|
||||||
|
If birth/bathism date are not compatible, the returned list will have MsgBirthDate
|
||||||
|
If birth place are not compatible, the returned list will have MsgBirthPlace *)
|
||||||
|
let compatible_birth p1 p2 =
|
||||||
|
let get_birth person =
|
||||||
|
if person.birth = Date.cdate_None then person.baptism else person.birth
|
||||||
|
in
|
||||||
|
let birth1 = get_birth p1 in
|
||||||
|
let birth2 = get_birth p2 in
|
||||||
|
let res1 = if compatible_cdates birth1 birth2 then [] else [ MsgBirthDate ] in
|
||||||
|
let res2 =
|
||||||
|
if compatible_str_field p1.birth_place p2.birth_place then []
|
||||||
|
else [ MsgBirthPlace ]
|
||||||
|
in
|
||||||
|
res1 @ res2
|
||||||
|
|
||||||
|
(** Same than before, but for death. Messages returned are
|
||||||
|
MsgDeathDate and MsgDeathPlace *)
|
||||||
|
let compatible_death p1 p2 =
|
||||||
|
let bool1 =
|
||||||
|
p1.death = p2.death
|
||||||
|
||
|
||||||
|
match (p1.death, p2.death) with
|
||||||
|
| Death (_, cdate1), Death (_, cdate2) ->
|
||||||
|
let date1 = Date.date_of_cdate cdate1 in
|
||||||
|
let date2 = Date.date_of_cdate cdate2 in
|
||||||
|
compatible_dates date1 date2
|
||||||
|
| NotDead, _
|
||||||
|
| DeadYoung, Death (_, _)
|
||||||
|
| DeadDontKnowWhen, (Death (_, _) | DeadYoung | DeadDontKnowWhen)
|
||||||
|
| DontKnowIfDead, _ ->
|
||||||
|
true
|
||||||
|
| _ -> (* S: avoid non-exhaustive pattern matching *) false
|
||||||
|
in
|
||||||
|
let res1 = if bool1 then [] else [ MsgDeathDate ] in
|
||||||
|
let res2 =
|
||||||
|
if compatible_str_field p1.death_place p2.death_place then []
|
||||||
|
else [ MsgDeathPlace ]
|
||||||
|
in
|
||||||
|
res1 @ res2
|
||||||
|
|
||||||
|
(** [compatible_sexes p1 p2]
|
||||||
|
Returns [] if `p1` and `p2` have the same sex, [MsgSex] otherwise. *)
|
||||||
|
let compatible_sexes p1 p2 = if p1.sex = p2.sex then [] else [ MsgSex ]
|
||||||
|
|
||||||
|
(** [compatible_occupations p1 p2]
|
||||||
|
Returns [] if `p1` and `p2` have compatible occupations, [MsgOccupation] otherwise. *)
|
||||||
|
let compatible_occupations p1 p2 =
|
||||||
|
if compatible_str_field p1.occupation p2.occupation then []
|
||||||
|
else [ MsgOccupation ]
|
||||||
|
|
||||||
|
(** Checks if two persons' names are compatible wrt. their eventual aliases and returns a
|
||||||
|
list of messages.
|
||||||
|
If first names are not compatible, the returned list will have MsgFirstName.
|
||||||
|
If surnames are not compatible, the returned list will have MsgSurname. *)
|
||||||
|
let compatible_persons_ligth base1 base2 p1 p2 =
|
||||||
|
let fn1 = sou base1 p1.first_name in
|
||||||
|
let fn2 = sou base2 p2.first_name in
|
||||||
|
let afn2 = fn2 :: List.map (sou base2) p2.first_names_aliases in
|
||||||
|
let sn1 = sou base1 p1.surname in
|
||||||
|
let sn2 = sou base2 p2.surname in
|
||||||
|
let asn2 = sn2 :: List.map (sou base2) p2.surnames_aliases in
|
||||||
|
let res1 = if compatible_names fn1 afn2 then [] else [ MsgFirstName ] in
|
||||||
|
let res2 = if compatible_names sn1 asn2 then [] else [ MsgSurname ] in
|
||||||
|
res1 @ res2
|
||||||
|
|
||||||
|
(** Checks if two persons are compatible and returns all the messages associated
|
||||||
|
to the compatiblity of their name, sex, birth, death and occupation. *)
|
||||||
|
let compatible_persons base1 base2 p1 p2 =
|
||||||
|
compatible_persons_ligth base1 base2 p1 p2
|
||||||
|
@ compatible_sexes p1 p2 @ compatible_birth p1 p2 @ compatible_death p1 p2
|
||||||
|
@ compatible_occupations p1 p2
|
||||||
|
|
||||||
|
(** [find_compatible_persons_ligth base1 base2 iper1 iper2_list]
|
||||||
|
Returns the sublist of persons of `iper2_list` that are compatible with
|
||||||
|
`iper1` (only checking names). *)
|
||||||
|
let rec find_compatible_persons_ligth base1 base2 iper1 iper2_list =
|
||||||
|
(* S: not tail recursive, could be *)
|
||||||
|
match iper2_list with
|
||||||
|
| [] -> []
|
||||||
|
| head :: rest ->
|
||||||
|
let p1 = gen_person_of_person (poi base1 iper1) in
|
||||||
|
let p2 = gen_person_of_person (poi base2 head) in
|
||||||
|
let c_rest = find_compatible_persons_ligth base1 base2 iper1 rest in
|
||||||
|
if compatible_persons_ligth base1 base2 p1 p2 = [] then head :: c_rest
|
||||||
|
else c_rest
|
||||||
|
|
||||||
|
(** Same than before, but with full compatibility ( name, sex, birth, death and
|
||||||
|
occupation) *)
|
||||||
|
let rec find_compatible_persons base1 base2 iper1 iper2_list =
|
||||||
|
match iper2_list with
|
||||||
|
| [] -> []
|
||||||
|
| head :: rest ->
|
||||||
|
let p1 = gen_person_of_person (poi base1 iper1) in
|
||||||
|
let p2 = gen_person_of_person (poi base2 head) in
|
||||||
|
let c_rest = find_compatible_persons base1 base2 iper1 rest in
|
||||||
|
if compatible_persons base1 base2 p1 p2 = [] then head :: c_rest
|
||||||
|
else c_rest
|
||||||
|
|
||||||
|
(** Checks if the spouse of the persons (whose id are in argument) are
|
||||||
|
compatible (only checking names) and returns the associated messages list. *)
|
||||||
|
let compatible_unions base1 base2 iper1 iper2 ifam1 ifam2 =
|
||||||
|
let get_spouse base iper ifam =
|
||||||
|
let f = foi base ifam in
|
||||||
|
if iper = get_father f then poi base (get_mother f)
|
||||||
|
else poi base (get_father f)
|
||||||
|
in
|
||||||
|
let spouse1 = gen_person_of_person (get_spouse base1 iper1 ifam1) in
|
||||||
|
let spouse2 = gen_person_of_person (get_spouse base2 iper2 ifam2) in
|
||||||
|
compatible_persons_ligth base1 base2 spouse1 spouse2
|
||||||
|
|
||||||
|
(** [find_compatible_unions base1 base2 iper1 iper2_list ifam1 ifam2_list]
|
||||||
|
Returns the sublist of families of `ifam2_list` whose union is compatible
|
||||||
|
(in the sense of `compatible_unions`). *)
|
||||||
|
let rec find_compatible_unions base1 base2 iper1 iper2 ifam1 ifam2_list =
|
||||||
|
match ifam2_list with
|
||||||
|
| [] -> []
|
||||||
|
| head :: rest ->
|
||||||
|
let c_rest = find_compatible_unions base1 base2 iper1 iper2 ifam1 rest in
|
||||||
|
if compatible_unions base1 base2 iper1 iper2 ifam1 head = [] then
|
||||||
|
head :: c_rest
|
||||||
|
else c_rest
|
||||||
|
|
||||||
|
(** [compatible_divorces d1 d2]
|
||||||
|
Returns true if divorces are compatible, i.e. if both divorced, then
|
||||||
|
checking date compatibility, if d1 is a divorce and d2 is not returns
|
||||||
|
false, otherwise returns true. *)
|
||||||
|
let compatible_divorces d1 d2 =
|
||||||
|
match (d1, d2) with
|
||||||
|
| Divorced cdate1, Divorced cdate2 -> compatible_cdates cdate1 cdate2
|
||||||
|
| Divorced _, _ -> false
|
||||||
|
| _ -> true
|
||||||
|
|
||||||
|
(** Checks the compatibility of marriages (mariage date, divorce
|
||||||
|
and mariage place), then print the list of messages calculated. *)
|
||||||
|
let compatible_marriages base1 base2 ifam1 ifam2 =
|
||||||
|
let f1 = gen_family_of_family (foi base1 ifam1) in
|
||||||
|
let f2 = gen_family_of_family (foi base2 ifam2) in
|
||||||
|
let res1 =
|
||||||
|
if compatible_cdates f1.marriage f2.marriage then []
|
||||||
|
else [ MsgMarriageDate ]
|
||||||
|
in
|
||||||
|
let res2 =
|
||||||
|
if compatible_divorces f1.divorce f2.divorce then [] else [ MsgDivorce ]
|
||||||
|
in
|
||||||
|
let res3 =
|
||||||
|
if compatible_str_field f1.marriage_place f2.marriage_place then []
|
||||||
|
else [ MsgMarriagePlace ]
|
||||||
|
in
|
||||||
|
let res = res1 @ res2 @ res3 in
|
||||||
|
if res = [] then () else print_f_messages base1 base2 ifam1 ifam2 res
|
||||||
|
|
||||||
|
(** Calculates the compatibility of two persons and prints the associated
|
||||||
|
messages *)
|
||||||
|
let pdiff base1 base2 iper1 iper2 =
|
||||||
|
let p1 = gen_person_of_person (poi base1 iper1) in
|
||||||
|
let p2 = gen_person_of_person (poi base2 iper2) in
|
||||||
|
let res = compatible_persons base1 base2 p1 p2 in
|
||||||
|
if res = [] then () else print_p_messages base1 base2 iper1 iper2 res
|
||||||
|
|
||||||
|
(** Calculates the compatibility of two persons' families and prints the
|
||||||
|
associated messages. *)
|
||||||
|
let compatible_parents base1 base2 iper1 iper2 =
|
||||||
|
let a1 = get_parents (poi base1 iper1) in
|
||||||
|
let a2 = get_parents (poi base2 iper2) in
|
||||||
|
match (a1, a2) with
|
||||||
|
| Some ifam1, Some ifam2 ->
|
||||||
|
let f1 = foi base1 ifam1 in
|
||||||
|
let f2 = foi base2 ifam2 in
|
||||||
|
let _ = pdiff base1 base2 (get_father f1) (get_father f2) in
|
||||||
|
let _ = pdiff base1 base2 (get_mother f1) (get_mother f2) in
|
||||||
|
compatible_marriages base1 base2 ifam1 ifam2
|
||||||
|
| None, _ -> ()
|
||||||
|
| Some _, None ->
|
||||||
|
print_p_messages base1 base2 iper1 iper2 [ MsgParentsMissing ]
|
||||||
|
|
||||||
|
(** Checks che compatibility of two persons and their families, and prints it.
|
||||||
|
This is performed recursively through their descendants *)
|
||||||
|
let rec ddiff base1 base2 iper1 iper2 d_tab =
|
||||||
|
(* S: Simplify with statement:
|
||||||
|
let ddiff iper1 iper2 = ddiff base1 base2 iper1 iper2 d_tab *)
|
||||||
|
let d_check = Gwdb.Marker.get d_tab iper1 in
|
||||||
|
if List.mem iper2 d_check then ()
|
||||||
|
else
|
||||||
|
let _ = Gwdb.Marker.set d_tab iper1 (iper2 :: d_check) in
|
||||||
|
let spouse f iper =
|
||||||
|
if iper = get_father f then get_mother f else get_father f
|
||||||
|
in
|
||||||
|
let udiff base1 base2 iper1 iper2 ifam1 ifam2 =
|
||||||
|
let fd b1 b2 ip2_list ip1 =
|
||||||
|
match find_compatible_persons_ligth b1 b2 ip1 ip2_list with
|
||||||
|
| [ ip2 ] -> ddiff base1 base2 ip1 ip2 d_tab
|
||||||
|
| [] -> print_p_messages base1 base2 iper1 iper2 [ MsgChildMissing ip1 ]
|
||||||
|
| rest_list -> (
|
||||||
|
match find_compatible_persons b1 b2 ip1 rest_list with
|
||||||
|
| [ best_ip2 ] -> ddiff base1 base2 ip1 best_ip2 d_tab
|
||||||
|
| [] -> print_p_messages base1 base2 iper1 iper2 [ MsgBadChild ip1 ]
|
||||||
|
| _ -> print_p_messages base1 base2 iper1 iper2 [ MsgChildren ip1 ])
|
||||||
|
in
|
||||||
|
let f1 = foi base1 ifam1 in
|
||||||
|
let f2 = foi base2 ifam2 in
|
||||||
|
let p1 = spouse f1 iper1 in
|
||||||
|
let p2 = spouse f2 iper2 in
|
||||||
|
let d1 = Array.to_list (get_children (foi base1 ifam1)) in
|
||||||
|
let d2 = Array.to_list (get_children (foi base2 ifam2)) in
|
||||||
|
pdiff base1 base2 p1 p2;
|
||||||
|
List.iter (fd base1 base2 d2) d1
|
||||||
|
in
|
||||||
|
let fu b1 b2 ifam2_list ifam1 =
|
||||||
|
match find_compatible_unions b1 b2 iper1 iper2 ifam1 ifam2_list with
|
||||||
|
| [ ifam2 ] ->
|
||||||
|
compatible_marriages b1 b2 ifam1 ifam2;
|
||||||
|
compatible_parents b1 b2
|
||||||
|
(spouse (foi base1 ifam1) iper1)
|
||||||
|
(spouse (foi base2 ifam2) iper2);
|
||||||
|
udiff b1 b2 iper1 iper2 ifam1 ifam2
|
||||||
|
| [] ->
|
||||||
|
print_p_messages base1 base2 iper1 iper2
|
||||||
|
[ MsgSpouseMissing (spouse (foi base1 ifam1) iper1) ]
|
||||||
|
| _ ->
|
||||||
|
print_p_messages base1 base2 iper1 iper2
|
||||||
|
[ MsgSpouses (spouse (foi base1 ifam1) iper1) ]
|
||||||
|
in
|
||||||
|
let u1 = Array.to_list (get_family (poi base1 iper1)) in
|
||||||
|
let u2 = Array.to_list (get_family (poi base2 iper2)) in
|
||||||
|
pdiff base1 base2 iper1 iper2;
|
||||||
|
List.iter (fu base1 base2 u2) u1
|
||||||
|
|
||||||
|
(** Returns the eldest persons on the base starting from the persons in argument. *)
|
||||||
|
let rec find_top base1 base2 iper1 iper2 =
|
||||||
|
let p1 = gen_person_of_person (poi base1 iper1) in
|
||||||
|
let p2 = gen_person_of_person (poi base2 iper2) in
|
||||||
|
if compatible_persons_ligth base1 base2 p1 p2 = [] then
|
||||||
|
let a1 = get_parents (poi base1 iper1) in
|
||||||
|
let a2 = get_parents (poi base2 iper2) in
|
||||||
|
match (a1, a2) with
|
||||||
|
| Some ifam1, Some ifam2 ->
|
||||||
|
let f1 = foi base1 ifam1 in
|
||||||
|
let f2 = foi base2 ifam2 in
|
||||||
|
let f_top_list = find_top base1 base2 (get_father f1) (get_father f2) in
|
||||||
|
let m_top_list = find_top base1 base2 (get_mother f1) (get_mother f2) in
|
||||||
|
f_top_list @ m_top_list
|
||||||
|
| _ -> [ (iper1, iper2) ]
|
||||||
|
else (
|
||||||
|
Printf.printf " Warning: %s doesn't match %s%s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
(person_link !in_file2 base2 iper2 "base2")
|
||||||
|
!cr;
|
||||||
|
[])
|
||||||
|
|
||||||
|
(** Same than ddiff, but starting from the eldest ancestors from the persons in argument *)
|
||||||
|
let addiff base1 base2 iper1 iper2 d_tab =
|
||||||
|
let topdiff (iper1, iper2) =
|
||||||
|
Printf.printf "==> %s / %s%s"
|
||||||
|
(person_link !in_file1 base1 iper1 "base1")
|
||||||
|
(person_link !in_file2 base2 iper2 "base2")
|
||||||
|
!cr;
|
||||||
|
ddiff base1 base2 iper1 iper2 d_tab
|
||||||
|
in
|
||||||
|
Printf.printf "Building top list...%s" !cr;
|
||||||
|
let top_list = find_top base1 base2 iper1 iper2 in
|
||||||
|
Printf.printf "Top list built.%s" !cr;
|
||||||
|
List.iter topdiff top_list
|
||||||
|
|
||||||
|
(* Main *)
|
||||||
|
|
||||||
|
let gwdiff base1 base2 iper1 iper2 d_mode ad_mode =
|
||||||
|
let desc_tab = Gwdb.iper_marker (Gwdb.ipers base1) [] in
|
||||||
|
match (d_mode, ad_mode) with
|
||||||
|
| true, _ | false, false -> ddiff base1 base2 iper1 iper2 desc_tab
|
||||||
|
| false, true -> addiff base1 base2 iper1 iper2 desc_tab
|
||||||
|
|
||||||
|
let p1_fn = ref ""
|
||||||
|
let p1_occ = ref 0
|
||||||
|
let p1_sn = ref ""
|
||||||
|
let p2_fn = ref ""
|
||||||
|
let p2_occ = ref 0
|
||||||
|
let p2_sn = ref ""
|
||||||
|
|
||||||
|
type arg_state = ASnone | ASwaitP1occ | ASwaitP1sn | ASwaitP2occ | ASwaitP2sn
|
||||||
|
|
||||||
|
let arg_state = ref ASnone
|
||||||
|
let mem = ref false
|
||||||
|
let d_mode = ref false
|
||||||
|
let ad_mode = ref false
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[
|
||||||
|
( "-1",
|
||||||
|
Arg.String
|
||||||
|
(fun s ->
|
||||||
|
p1_fn := s;
|
||||||
|
arg_state := ASwaitP1occ),
|
||||||
|
"<fn> <occ> <sn> : (mandatory) defines starting person in base1" );
|
||||||
|
( "-2",
|
||||||
|
Arg.String
|
||||||
|
(fun s ->
|
||||||
|
p2_fn := s;
|
||||||
|
arg_state := ASwaitP2occ),
|
||||||
|
"<fn> <occ> <sn> : (mandatory) defines starting person in base2" );
|
||||||
|
("-ad", Arg.Set ad_mode, ": checks descendants of all ascendants ");
|
||||||
|
("-d", Arg.Set d_mode, ": checks descendants (default)");
|
||||||
|
( "-html",
|
||||||
|
Arg.String
|
||||||
|
(fun s ->
|
||||||
|
html := true;
|
||||||
|
root := s),
|
||||||
|
"<root>: HTML format used for report" );
|
||||||
|
("-mem", Arg.Set mem, ": save memory space, but slower");
|
||||||
|
]
|
||||||
|
|
||||||
|
let anonfun s =
|
||||||
|
match !arg_state with
|
||||||
|
| ASnone ->
|
||||||
|
if !in_file1 = "" then in_file1 := s
|
||||||
|
else if !in_file2 = "" then in_file2 := s
|
||||||
|
else raise (Arg.Bad "Too much arguments")
|
||||||
|
| ASwaitP1occ -> (
|
||||||
|
try
|
||||||
|
p1_occ := int_of_string s;
|
||||||
|
arg_state := ASwaitP1sn
|
||||||
|
with Failure _ -> raise (Arg.Bad "Numeric value for occ (-1)!"))
|
||||||
|
| ASwaitP1sn ->
|
||||||
|
p1_sn := s;
|
||||||
|
arg_state := ASnone
|
||||||
|
| ASwaitP2occ -> (
|
||||||
|
try
|
||||||
|
p2_occ := int_of_string s;
|
||||||
|
arg_state := ASwaitP2sn
|
||||||
|
with Failure _ -> raise (Arg.Bad "Numeric value for occ (-2)!"))
|
||||||
|
| ASwaitP2sn ->
|
||||||
|
p2_sn := s;
|
||||||
|
arg_state := ASnone
|
||||||
|
|
||||||
|
let errmsg = "Usage: " ^ Sys.argv.(0) ^ " [options] base1 base2\nOptions are: "
|
||||||
|
|
||||||
|
let check_args () =
|
||||||
|
Arg.parse speclist anonfun errmsg;
|
||||||
|
if !in_file1 = "" then (
|
||||||
|
Printf.printf "Missing reference data base\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
if !in_file2 = "" then (
|
||||||
|
Printf.printf "Missing destination data base\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
if !p1_fn = "" then (
|
||||||
|
Printf.printf "-1 parameter is mandatory\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
if !p1_sn = "" then (
|
||||||
|
Printf.printf "Incomplete -1 parameter\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
if !p2_fn = "" then (
|
||||||
|
Printf.printf "-2 parameter is mandatory\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2);
|
||||||
|
if !p2_sn = "" then (
|
||||||
|
Printf.printf "Incomplete -2 parameter\n";
|
||||||
|
Printf.printf "Use option -help for usage\n";
|
||||||
|
flush stdout;
|
||||||
|
exit 2)
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
let _ = check_args () in
|
||||||
|
let _ = if not !html then cr := "\n" else cr := "<BR>\n" in
|
||||||
|
let load_base file =
|
||||||
|
let base = open_base file in
|
||||||
|
let () = load_ascends_array base in
|
||||||
|
let () = load_strings_array base in
|
||||||
|
let () =
|
||||||
|
if not !mem then
|
||||||
|
let () = load_unions_array base in
|
||||||
|
let () = load_couples_array base in
|
||||||
|
let () = load_descends_array base in
|
||||||
|
()
|
||||||
|
in
|
||||||
|
base
|
||||||
|
in
|
||||||
|
(* Reference base *)
|
||||||
|
let base1 = load_base !in_file1 in
|
||||||
|
(* Destination base *)
|
||||||
|
let base2 = if !in_file1 != !in_file2 then load_base !in_file2 else base1 in
|
||||||
|
let iper1 = person_of_key base1 !p1_fn !p1_sn !p1_occ in
|
||||||
|
let iper2 = person_of_key base2 !p2_fn !p2_sn !p2_occ in
|
||||||
|
if !html then Printf.printf "<BODY>\n";
|
||||||
|
(match (iper1, iper2) with
|
||||||
|
| None, _ ->
|
||||||
|
Printf.printf "Cannot find person %s.%d %s in reference base" !p1_fn
|
||||||
|
!p1_occ !p1_sn
|
||||||
|
| _, None ->
|
||||||
|
Printf.printf "Cannot find person %s.%d %s in destination base" !p2_fn
|
||||||
|
!p2_occ !p2_sn
|
||||||
|
| Some iper1, Some iper2 -> gwdiff base1 base2 iper1 iper2 !d_mode !ad_mode);
|
||||||
|
if !html then Printf.printf "</BODY>\n"
|
||||||
|
|
||||||
|
let _ = Printexc.print main ()
|
6
bin/gwexport/dune
Normal file
6
bin/gwexport/dune
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(library
|
||||||
|
(name gwexport_lib)
|
||||||
|
(public_name geneweb.gwexport_lib)
|
||||||
|
(wrapped false)
|
||||||
|
(libraries geneweb)
|
||||||
|
(modules gwexport))
|
456
bin/gwexport/gwexport.ml
Normal file
456
bin/gwexport/gwexport.ml
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
open Geneweb
|
||||||
|
open Gwdb
|
||||||
|
|
||||||
|
type gwexport_charset = Ansel | Ansi | Ascii | Utf8
|
||||||
|
|
||||||
|
type gwexport_opts = {
|
||||||
|
asc : int option;
|
||||||
|
ascdesc : int option;
|
||||||
|
base : (string * base) option;
|
||||||
|
censor : int;
|
||||||
|
charset : gwexport_charset;
|
||||||
|
desc : int option;
|
||||||
|
img_base_path : string;
|
||||||
|
keys : string list;
|
||||||
|
mem : bool;
|
||||||
|
no_notes : [ `none | `nn | `nnn ];
|
||||||
|
no_picture : bool;
|
||||||
|
oc : string * (string -> unit) * (unit -> unit);
|
||||||
|
parentship : bool;
|
||||||
|
picture_path : bool;
|
||||||
|
source : string option;
|
||||||
|
surnames : string list;
|
||||||
|
verbose : bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_opts =
|
||||||
|
{
|
||||||
|
asc = None;
|
||||||
|
ascdesc = None;
|
||||||
|
base = None;
|
||||||
|
censor = 0;
|
||||||
|
charset = Utf8;
|
||||||
|
desc = None;
|
||||||
|
img_base_path = "";
|
||||||
|
keys = [];
|
||||||
|
mem = false;
|
||||||
|
no_notes = `none;
|
||||||
|
no_picture = false;
|
||||||
|
oc = ("", prerr_string, fun () -> close_out stderr);
|
||||||
|
parentship = false;
|
||||||
|
picture_path = false;
|
||||||
|
source = None;
|
||||||
|
surnames = [];
|
||||||
|
verbose = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let errmsg = "Usage: " ^ Sys.argv.(0) ^ " <BASE> [OPT]"
|
||||||
|
|
||||||
|
let anonfun c s =
|
||||||
|
if !c.base = None then (
|
||||||
|
Secure.set_base_dir (Filename.dirname s);
|
||||||
|
c := { !c with base = Some (s, Gwdb.open_base s) })
|
||||||
|
else raise (Arg.Bad "Cannot treat several databases")
|
||||||
|
|
||||||
|
let speclist c =
|
||||||
|
[
|
||||||
|
( "-a",
|
||||||
|
Arg.Int (fun s -> c := { !c with asc = Some s }),
|
||||||
|
"<N> maximum generation of the root's ascendants" );
|
||||||
|
( "-ad",
|
||||||
|
Arg.Int (fun s -> c := { !c with ascdesc = Some s }),
|
||||||
|
"<N> maximum generation of the root's ascendants descendants" );
|
||||||
|
( "-key",
|
||||||
|
Arg.String (fun s -> c := { !c with keys = s :: !c.keys }),
|
||||||
|
"<KEY> key reference of root person. Used for -a/-d options. Can be used \
|
||||||
|
multiple times. Key format is \"First Name.occ SURNAME\"" );
|
||||||
|
( "-c",
|
||||||
|
Arg.Int (fun s -> c := { !c with censor = s }),
|
||||||
|
"<NUM>: when a person is born less than <num> years ago, it is not \
|
||||||
|
exported unless it is Public. All the spouses and descendants are also \
|
||||||
|
censored." );
|
||||||
|
( "-charset",
|
||||||
|
Arg.String
|
||||||
|
(fun s ->
|
||||||
|
c :=
|
||||||
|
{
|
||||||
|
!c with
|
||||||
|
charset =
|
||||||
|
(match s with
|
||||||
|
| "ASCII" -> Ascii
|
||||||
|
| "ANSEL" -> Ansel
|
||||||
|
| "ANSI" -> Ansi
|
||||||
|
| "UTF-8" -> Utf8
|
||||||
|
| _ -> raise (Arg.Bad "bad -charset value"));
|
||||||
|
}),
|
||||||
|
"[ASCII|ANSEL|ANSI|UTF-8] set charset; default is UTF-8" );
|
||||||
|
( "-d",
|
||||||
|
Arg.Int (fun s -> c := { !c with desc = Some s }),
|
||||||
|
"<N> maximum generation of the root's descendants." );
|
||||||
|
( "-mem",
|
||||||
|
Arg.Unit (fun () -> c := { !c with mem = true }),
|
||||||
|
" save memory space, but slower." );
|
||||||
|
( "-nn",
|
||||||
|
Arg.Unit
|
||||||
|
(fun () -> if !c.no_notes = `none then c := { !c with no_notes = `nn }),
|
||||||
|
" no (database) notes." );
|
||||||
|
( "-nnn",
|
||||||
|
Arg.Unit (fun () -> c := { !c with no_notes = `nnn }),
|
||||||
|
" no notes (implies -nn)." );
|
||||||
|
( "-nopicture",
|
||||||
|
Arg.Unit (fun () -> c := { !c with no_picture = true }),
|
||||||
|
" don't extract individual picture." );
|
||||||
|
( "-o",
|
||||||
|
Arg.String
|
||||||
|
(fun s ->
|
||||||
|
let oc = open_out s in
|
||||||
|
c := { !c with oc = (s, output_string oc, fun () -> close_out oc) }),
|
||||||
|
"<GED> output file name (default: stdout)." );
|
||||||
|
( "-parentship",
|
||||||
|
Arg.Unit (fun () -> c := { !c with parentship = true }),
|
||||||
|
" select individuals involved in parentship computation between pairs of \
|
||||||
|
keys. Pairs must be defined with -key option, descendant first: e.g. \
|
||||||
|
-key \"Descendant.0 SURNAME\" -key \"Ancestor.0 SURNAME\". If multiple \
|
||||||
|
pair are provided, union of persons are returned." );
|
||||||
|
( "-picture-path",
|
||||||
|
Arg.Unit (fun () -> c := { !c with picture_path = true }),
|
||||||
|
" extract pictures path." );
|
||||||
|
( "-s",
|
||||||
|
Arg.String (fun x -> c := { !c with surnames = x :: !c.surnames }),
|
||||||
|
"<SN> select this surname (option usable several times, union of \
|
||||||
|
surnames will be used)." );
|
||||||
|
( "-source",
|
||||||
|
Arg.String (fun x -> c := { !c with source = Some x }),
|
||||||
|
"<SRC> replace individuals and families sources. Also delete event \
|
||||||
|
sources." );
|
||||||
|
("-v", Arg.Unit (fun () -> c := { !c with verbose = true }), " verbose");
|
||||||
|
]
|
||||||
|
|
||||||
|
module IPS = Util.IperSet
|
||||||
|
module IFS = Util.IfamSet
|
||||||
|
|
||||||
|
(* S: Does it mean private persons whose birth year is before 'max_year'
|
||||||
|
are uncensored? *)
|
||||||
|
|
||||||
|
(** [is_censored_person max_year person_name]
|
||||||
|
Returns [true] iff the person has a birth date that is after max_year and
|
||||||
|
its visibility is not public
|
||||||
|
*)
|
||||||
|
let is_censored_person threshold p =
|
||||||
|
match Date.cdate_to_dmy_opt (get_birth p) with
|
||||||
|
| None -> false
|
||||||
|
| Some dmy -> dmy.Adef.year >= threshold && get_access p != Def.Public
|
||||||
|
|
||||||
|
(** [is_censored_couple base max_year family]
|
||||||
|
Returns [true] if either the father or the mother of a given family in the
|
||||||
|
base is censored
|
||||||
|
*)
|
||||||
|
let is_censored_couple base threshold cpl =
|
||||||
|
(is_censored_person threshold @@ poi base (get_father cpl))
|
||||||
|
|| (is_censored_person threshold @@ poi base (get_mother cpl))
|
||||||
|
|
||||||
|
(* The following functions are utils set people as "censored" by marking them.
|
||||||
|
Censoring a person consists in setting a mark defined as:
|
||||||
|
`Marker.get pmark p lor flag`
|
||||||
|
|
||||||
|
This gets the current mark, being 0 or 1, and `lor`s it with `flag` which is `1`.
|
||||||
|
TODO: replace integer markers by booleans
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** Marks a censored person *)
|
||||||
|
let censor_person base pmark flag threshold p no_check =
|
||||||
|
let ps = poi base p in
|
||||||
|
if no_check || is_censored_person threshold ps then
|
||||||
|
Marker.set pmark p (Marker.get pmark p lor flag)
|
||||||
|
|
||||||
|
(** Marks all the members of a family that are censored.
|
||||||
|
If a couple is censored, its parents and all its descendants are marked.
|
||||||
|
*)
|
||||||
|
let rec censor_family base pmark fmark flag threshold i no_check =
|
||||||
|
let censor_unions p =
|
||||||
|
let uni = poi base p in
|
||||||
|
Array.iter
|
||||||
|
(fun ifam ->
|
||||||
|
censor_family base pmark fmark flag threshold ifam true;
|
||||||
|
censor_person base pmark flag threshold p true)
|
||||||
|
(get_family uni)
|
||||||
|
in
|
||||||
|
let censor_descendants f =
|
||||||
|
let des = foi base f in
|
||||||
|
Array.iter
|
||||||
|
(fun iper -> if Marker.get pmark iper = 0 then censor_unions iper)
|
||||||
|
(get_children des)
|
||||||
|
in
|
||||||
|
let all_families_censored p =
|
||||||
|
(* FIXME: replace with forall *)
|
||||||
|
let uni = poi base p in
|
||||||
|
Array.fold_left
|
||||||
|
(fun check ifam -> check && Marker.get fmark ifam = 0)
|
||||||
|
true (get_family uni)
|
||||||
|
in
|
||||||
|
let censor_spouse iper =
|
||||||
|
if all_families_censored iper then
|
||||||
|
Marker.set pmark iper (Marker.get pmark iper lor flag)
|
||||||
|
(* S: Replace this line by `censor_person`? *)
|
||||||
|
in
|
||||||
|
if Marker.get fmark i = 0 then
|
||||||
|
let fam = foi base i in
|
||||||
|
if no_check || is_censored_couple base threshold fam then (
|
||||||
|
Marker.set fmark i (Marker.get fmark i lor flag);
|
||||||
|
censor_spouse (get_father fam);
|
||||||
|
censor_spouse (get_mother fam);
|
||||||
|
censor_descendants i)
|
||||||
|
|
||||||
|
(** Marks all the families that are censored in the given base. *)
|
||||||
|
let censor_base base pmark fmark flag threshold =
|
||||||
|
Collection.iter
|
||||||
|
(fun i -> censor_family base pmark fmark flag threshold i false)
|
||||||
|
(ifams base);
|
||||||
|
Collection.iter
|
||||||
|
(fun i -> censor_person base pmark flag threshold i false)
|
||||||
|
(ipers base)
|
||||||
|
|
||||||
|
(** Set non visible persons and families as censored *)
|
||||||
|
let restrict_base base per_tab fam_tab flag =
|
||||||
|
(* Starts by censoring non visible persons of the base *)
|
||||||
|
Collection.iter
|
||||||
|
(fun i ->
|
||||||
|
if base_visible_get base (fun _ -> false) i then
|
||||||
|
Marker.set per_tab i (Marker.get per_tab i lor flag))
|
||||||
|
(* S: replace by `censor_person` ? *)
|
||||||
|
(ipers base);
|
||||||
|
|
||||||
|
Collection.iter
|
||||||
|
(fun i ->
|
||||||
|
let fam = foi base i in
|
||||||
|
let des_visible =
|
||||||
|
(* There exists a children of the family that is not censored *)
|
||||||
|
(* FIXME: replace with exists *)
|
||||||
|
Array.fold_left
|
||||||
|
(fun check iper -> check || Marker.get per_tab iper = 0)
|
||||||
|
false (get_children fam)
|
||||||
|
in
|
||||||
|
let cpl_not_visible =
|
||||||
|
(* Father or mother is censored *)
|
||||||
|
Marker.get per_tab (get_father fam) <> 0
|
||||||
|
|| Marker.get per_tab (get_mother fam) <> 0
|
||||||
|
in
|
||||||
|
(* If all the children, father and mother are censored, then censor family *)
|
||||||
|
if (not des_visible) && cpl_not_visible then
|
||||||
|
Marker.set fam_tab i (Marker.get fam_tab i lor flag))
|
||||||
|
(ifams base)
|
||||||
|
|
||||||
|
(** [select_asc conf base max_gen ips]
|
||||||
|
Returns all the ancestors of persons in the list `ips` up to the `max_gen`
|
||||||
|
generation. *)
|
||||||
|
let select_asc conf base max_gen ips =
|
||||||
|
let rec loop_asc (gen : int) set ip =
|
||||||
|
if not @@ IPS.mem ip set then
|
||||||
|
let set = IPS.add ip set in
|
||||||
|
let p = Util.pget conf base ip in
|
||||||
|
if gen < max_gen then
|
||||||
|
match get_parents p with
|
||||||
|
| Some ifam ->
|
||||||
|
let cpl = foi base ifam in
|
||||||
|
let set = loop_asc (gen + 1) set (get_father cpl) in
|
||||||
|
loop_asc (gen + 1) set (get_mother cpl)
|
||||||
|
| _ -> set
|
||||||
|
else set
|
||||||
|
else set
|
||||||
|
in
|
||||||
|
List.fold_left (loop_asc 0) IPS.empty ips
|
||||||
|
|
||||||
|
(* S: only used by `select_surnames` in a List.iter *)
|
||||||
|
(* Should it use search engine functions? *)
|
||||||
|
|
||||||
|
(** [select_surname nase pmark fmark surname]
|
||||||
|
Sets a `true` marker to families whose mother or father that
|
||||||
|
match the given surname. Propagates the mark to children
|
||||||
|
that have this surname.
|
||||||
|
*)
|
||||||
|
let select_surname base pmark fmark surname =
|
||||||
|
let surname = Name.strip_lower surname in
|
||||||
|
Collection.iter
|
||||||
|
(fun i ->
|
||||||
|
let fam = foi base i in
|
||||||
|
let fath = poi base (get_father fam) in
|
||||||
|
let moth = poi base (get_mother fam) in
|
||||||
|
if
|
||||||
|
Name.strip_lower (sou base (get_surname fath)) = surname
|
||||||
|
|| Name.strip_lower (sou base (get_surname moth)) = surname
|
||||||
|
then (
|
||||||
|
Marker.set fmark i true;
|
||||||
|
Marker.set pmark (get_father fam) true;
|
||||||
|
Marker.set pmark (get_mother fam) true;
|
||||||
|
Array.iter
|
||||||
|
(fun ic ->
|
||||||
|
let p = poi base ic in
|
||||||
|
if
|
||||||
|
(not (Marker.get pmark ic))
|
||||||
|
&& Name.strip_lower (sou base (get_surname p)) = surname
|
||||||
|
then Marker.set pmark ic true)
|
||||||
|
(get_children fam)))
|
||||||
|
(ifams base)
|
||||||
|
|
||||||
|
(** [select_surnames base surnames]
|
||||||
|
Calls `select_surname` on every family that have the given surnames.
|
||||||
|
Returns two functions:
|
||||||
|
* the first takes a person and returns `true` iff it has been selected
|
||||||
|
* the second takes a family and returns `false` iff it has been selected
|
||||||
|
*)
|
||||||
|
let select_surnames base surnames : (iper -> bool) * (ifam -> bool) =
|
||||||
|
let pmark = Gwdb.iper_marker (Gwdb.ipers base) false in
|
||||||
|
let fmark = Gwdb.ifam_marker (Gwdb.ifams base) false in
|
||||||
|
List.iter (select_surname base pmark fmark) surnames;
|
||||||
|
((fun i -> Gwdb.Marker.get pmark i), fun i -> Gwdb.Marker.get fmark i)
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
(** [select_parentship base ip1 ip2]
|
||||||
|
Returns the set of common descendants of ip1 and the
|
||||||
|
ancestors of ip2 and the set of their families. *)
|
||||||
|
let select_parentship base ip1 ip2 =
|
||||||
|
let conf = Config.{ empty with wizard = true; bname = Gwdb.bname base } in
|
||||||
|
let asc = select_asc conf base max_int [ ip1 ] in
|
||||||
|
let desc = Util.select_desc conf base (-max_int) [ (ip2, 0) ] in
|
||||||
|
let ipers =
|
||||||
|
(* S: The intersection of asc and desc *)
|
||||||
|
if IPS.cardinal asc > Hashtbl.length desc then
|
||||||
|
Hashtbl.fold
|
||||||
|
(fun k _ acc -> if IPS.mem k asc then IPS.add k acc else acc)
|
||||||
|
desc IPS.empty
|
||||||
|
else
|
||||||
|
IPS.fold
|
||||||
|
(fun k acc -> if Hashtbl.mem desc k then IPS.add k acc else acc)
|
||||||
|
asc IPS.empty
|
||||||
|
in
|
||||||
|
let ifams =
|
||||||
|
(* S: families *)
|
||||||
|
IPS.fold
|
||||||
|
(fun iper acc ->
|
||||||
|
Array.fold_left
|
||||||
|
(fun acc ifam ->
|
||||||
|
if
|
||||||
|
IFS.mem ifam acc (* S: useless test? *)
|
||||||
|
|| not (IPS.mem (Gutil.spouse iper @@ foi base ifam) ipers)
|
||||||
|
(* S: is the partner of the
|
||||||
|
person not in ipers? *)
|
||||||
|
then acc
|
||||||
|
else IFS.add ifam acc)
|
||||||
|
acc
|
||||||
|
(get_family (poi base iper)))
|
||||||
|
ipers IFS.empty
|
||||||
|
in
|
||||||
|
(ipers, ifams)
|
||||||
|
|
||||||
|
(** [select_from_set ipers ifams]
|
||||||
|
Returns two functions :
|
||||||
|
* the first returns true if its input is in ipers
|
||||||
|
* the second returns true if its input is in ifams
|
||||||
|
*)
|
||||||
|
let select_from_set (ipers : IPS.t) (ifams : IFS.t) =
|
||||||
|
let sel_per i = IPS.mem i ipers in
|
||||||
|
let sel_fam i = IFS.mem i ifams in
|
||||||
|
(sel_per, sel_fam)
|
||||||
|
|
||||||
|
(** [select opts ips]
|
||||||
|
Return filters for [iper] and [ifam] to be used when exporting
|
||||||
|
a (portion of a) base.
|
||||||
|
*)
|
||||||
|
let select opts ips =
|
||||||
|
match opts.base with
|
||||||
|
| None -> raise (Arg.Bad "Missing base name. Use option -help for usage")
|
||||||
|
| Some (_, base) ->
|
||||||
|
let ips =
|
||||||
|
List.rev_append ips
|
||||||
|
@@ Mutil.filter_map (Gutil.person_of_string_key base) opts.keys
|
||||||
|
in
|
||||||
|
let not_censor_p, not_censor_f =
|
||||||
|
if opts.censor <> 0 then (
|
||||||
|
let pmark = iper_marker (ipers base) 0 in
|
||||||
|
let fmark = ifam_marker (ifams base) 0 in
|
||||||
|
(if opts.censor = -1 then restrict_base base pmark fmark 1
|
||||||
|
else
|
||||||
|
let tm = Unix.localtime (Unix.time ()) in
|
||||||
|
let threshold = 1900 + tm.Unix.tm_year - opts.censor in
|
||||||
|
censor_base base pmark fmark 1 threshold);
|
||||||
|
((fun i -> Marker.get pmark i = 0), fun i -> Marker.get fmark i = 0))
|
||||||
|
else ((fun _ -> true), fun _ -> true)
|
||||||
|
in
|
||||||
|
let conf = Config.{ empty with wizard = true } in
|
||||||
|
let sel_per, sel_fam =
|
||||||
|
(* S: a lot of redundant tests are done here, would be simpler with
|
||||||
|
pattern matchings and factorization. *)
|
||||||
|
if opts.ascdesc <> None || opts.desc <> None then (
|
||||||
|
assert (opts.censor = 0);
|
||||||
|
let asc =
|
||||||
|
if opts.ascdesc <> None then Option.value ~default:max_int opts.asc
|
||||||
|
else Option.value ~default:0 opts.asc
|
||||||
|
in
|
||||||
|
let desc = -Option.value ~default:0 opts.desc in
|
||||||
|
let ht =
|
||||||
|
match opts.ascdesc with
|
||||||
|
| Some ascdesc ->
|
||||||
|
let ips = List.map (fun i -> (i, asc)) ips in
|
||||||
|
Util.select_mascdesc conf base ips ascdesc
|
||||||
|
| None ->
|
||||||
|
let ht = Hashtbl.create 0 in
|
||||||
|
IPS.iter
|
||||||
|
(fun i -> Hashtbl.add ht i (poi base i))
|
||||||
|
(select_asc conf base asc ips);
|
||||||
|
ht
|
||||||
|
in
|
||||||
|
let ht' =
|
||||||
|
let ips = List.map (fun i -> (i, 0)) ips in
|
||||||
|
Util.select_desc conf base desc ips
|
||||||
|
in
|
||||||
|
Hashtbl.iter (fun i p -> Hashtbl.replace ht i p) ht';
|
||||||
|
let ipers =
|
||||||
|
Hashtbl.fold (fun i _ ipers -> IPS.add i ipers) ht IPS.empty
|
||||||
|
in
|
||||||
|
let ifams =
|
||||||
|
IPS.fold
|
||||||
|
(fun iper acc ->
|
||||||
|
Array.fold_left
|
||||||
|
(fun acc ifam ->
|
||||||
|
if
|
||||||
|
IFS.mem ifam acc
|
||||||
|
|| not
|
||||||
|
(IPS.mem (Gutil.spouse iper @@ foi base ifam) ipers)
|
||||||
|
then acc
|
||||||
|
else IFS.add ifam acc)
|
||||||
|
acc
|
||||||
|
(get_family (poi base iper)))
|
||||||
|
ipers IFS.empty
|
||||||
|
in
|
||||||
|
let sel_per i = IPS.mem i ipers in
|
||||||
|
let sel_fam i = IFS.mem i ifams in
|
||||||
|
(sel_per, sel_fam))
|
||||||
|
else
|
||||||
|
match opts.asc with
|
||||||
|
(* opts.ascdesc = None && opts.desc = None *)
|
||||||
|
| Some asc ->
|
||||||
|
let ipers = select_asc conf base asc ips in
|
||||||
|
let per_sel i = IPS.mem i ipers in
|
||||||
|
let fam_sel i =
|
||||||
|
let f = foi base i in
|
||||||
|
per_sel (get_father f) && per_sel (get_mother f)
|
||||||
|
in
|
||||||
|
(per_sel, fam_sel)
|
||||||
|
| None ->
|
||||||
|
if opts.surnames <> [] then select_surnames base opts.surnames
|
||||||
|
else if opts.parentship then
|
||||||
|
let rec loop ipers ifams = function
|
||||||
|
| [] -> select_from_set ipers ifams
|
||||||
|
| k2 :: k1 :: tl ->
|
||||||
|
let ipers', ifams' = select_parentship base k1 k2 in
|
||||||
|
let ipers = IPS.fold IPS.add ipers ipers' in
|
||||||
|
let ifams = IFS.fold IFS.add ifams ifams' in
|
||||||
|
loop ipers ifams tl
|
||||||
|
| _ -> assert false
|
||||||
|
in
|
||||||
|
loop IPS.empty IFS.empty ips
|
||||||
|
else ((fun _ -> true), fun _ -> true)
|
||||||
|
in
|
||||||
|
( (fun i -> not_censor_p i && sel_per i),
|
||||||
|
fun i -> not_censor_f i && sel_fam i )
|
55
bin/gwexport/gwexport.mli
Normal file
55
bin/gwexport/gwexport.mli
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
type gwexport_charset = Ansel | Ansi | Ascii | Utf8
|
||||||
|
|
||||||
|
type gwexport_opts = {
|
||||||
|
asc : int option; (* Maximum generation of the root's ascendants *)
|
||||||
|
ascdesc : int option;
|
||||||
|
(* Maximum generation of the root's ascendants descendants *)
|
||||||
|
base : (string * Gwdb.base) option; (* The base analyzed *)
|
||||||
|
censor : int; (* Censors the base for 'n' years *)
|
||||||
|
charset : gwexport_charset; (* The charset of the export *)
|
||||||
|
desc : int option; (* Maximum generation of the root's descendants *)
|
||||||
|
img_base_path : string; (* Unused by this module (and not set by options) *)
|
||||||
|
keys : string list; (* Key reference of additional persons to select *)
|
||||||
|
mem : bool; (* Unused by this module *)
|
||||||
|
no_notes : [ `nn | `nnn | `none ];
|
||||||
|
(* Unused by this module
|
||||||
|
S: Consider simple ADTs *)
|
||||||
|
no_picture : bool; (* Unused by this module *)
|
||||||
|
oc : string * (string -> unit) * (unit -> unit); (* Unused by this module *)
|
||||||
|
parentship : bool;
|
||||||
|
(* If asc, ascdesc and desc are not set & parenting = true, then
|
||||||
|
select individuals involved in parentship between pair of keys
|
||||||
|
(/!\ assumes the input are pairs of keys) *)
|
||||||
|
picture_path : bool; (* Unused by this module *)
|
||||||
|
source : string option; (* Unused by this module *)
|
||||||
|
surnames : string list; (* Used to select persons by their surname *)
|
||||||
|
verbose : bool; (* Unused by this module *)
|
||||||
|
}
|
||||||
|
|
||||||
|
val default_opts : gwexport_opts
|
||||||
|
(** Default set of options *)
|
||||||
|
|
||||||
|
val speclist : gwexport_opts ref -> (Arg.key * Arg.spec * Arg.doc) list
|
||||||
|
(** Given a set of options, returns default command line arguments for selecting
|
||||||
|
elements from a base. The output of this function is the first input of
|
||||||
|
Arg.parse.
|
||||||
|
*)
|
||||||
|
(* Used for gwd2ged and gwu. *)
|
||||||
|
|
||||||
|
val anonfun : gwexport_opts ref -> Arg.anon_fun
|
||||||
|
(** [anonfun opts = fun base_name -> ...]
|
||||||
|
Given a set of options `opts` where `!opts.base` is uninitialized,
|
||||||
|
opens the dir `base_name` and initializes !opts.base with the base name.
|
||||||
|
The output of this function is the second argument of Arg.parse.
|
||||||
|
*)
|
||||||
|
(* Arg.anon_fun = string -> unit *)
|
||||||
|
|
||||||
|
val errmsg : Arg.usage_msg
|
||||||
|
(** Default error message.
|
||||||
|
This is the third argument of Arg.parse. *)
|
||||||
|
|
||||||
|
val select :
|
||||||
|
gwexport_opts -> Gwdb.iper list -> (Gwdb.iper -> bool) * (Gwdb.ifam -> bool)
|
||||||
|
(** [select opts ips]
|
||||||
|
Return filters for [iper] and [ifam] to be used when exporting a (portion of a) base.
|
||||||
|
*)
|
9
bin/gwgc/dune.in
Normal file
9
bin/gwgc/dune.in
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifdef GENEWEB_GWDB_LEGACY
|
||||||
|
(executable
|
||||||
|
(name gwgc)
|
||||||
|
(public_name geneweb.gwgc)
|
||||||
|
(modules gwgc)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(libraries unix str %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
)
|
||||||
|
#endif
|
27
bin/gwgc/gwgc.ml
Normal file
27
bin/gwgc/gwgc.ml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
let dry_run = ref false
|
||||||
|
let bname = ref ""
|
||||||
|
|
||||||
|
let speclist =
|
||||||
|
[ ("--dry-run", Arg.Set dry_run, " do not commit changes (only print)") ]
|
||||||
|
|
||||||
|
let anonfun i = bname := i
|
||||||
|
let usage = "Usage: " ^ Sys.argv.(0) ^ " [OPTION] base"
|
||||||
|
|
||||||
|
let () =
|
||||||
|
Arg.parse speclist anonfun usage;
|
||||||
|
let bname =
|
||||||
|
match !bname with
|
||||||
|
| "" ->
|
||||||
|
Arg.usage speclist usage;
|
||||||
|
exit 1
|
||||||
|
| s -> s
|
||||||
|
in
|
||||||
|
let dry_run = !dry_run in
|
||||||
|
Secure.set_base_dir (Filename.dirname bname);
|
||||||
|
Lock.control (Mutil.lock_file bname) true ~onerror:Lock.print_try_again
|
||||||
|
@@ fun () ->
|
||||||
|
let base = Database.opendb bname in
|
||||||
|
let p, f, s = Gwdb_gc.gc ~dry_run base in
|
||||||
|
Printf.printf
|
||||||
|
"%s:\n\tnb of persons: %d\n\tnb of families: %d\n\tnb of strings: %d\n"
|
||||||
|
bname (List.length p) (List.length f) (List.length s)
|
12
bin/gwrepl/data.mli
Normal file
12
bin/gwrepl/data.mli
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(* the array of etc/lib/XXX where XXX are either dependencies of geneweb or
|
||||||
|
geneweb/COMPONENT *)
|
||||||
|
val directories : string array
|
||||||
|
|
||||||
|
(* associations between file names and their (generated) contents: *)
|
||||||
|
val cmas : (string * string) array (* .cma *)
|
||||||
|
val cmis : (string * string) array (* .cmi *)
|
||||||
|
val shared : (string * string) array (* .so *)
|
||||||
|
|
||||||
|
(* An md5 of all the names of the files in [cmis] and [cmas] (not
|
||||||
|
their contents). *)
|
||||||
|
val md5 : string
|
43
bin/gwrepl/dune.in
Normal file
43
bin/gwrepl/dune.in
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
(library
|
||||||
|
(name gwrepl_deps)
|
||||||
|
(flags -linkall)
|
||||||
|
(libraries
|
||||||
|
stdlib
|
||||||
|
str
|
||||||
|
unix
|
||||||
|
geneweb_core
|
||||||
|
geneweb_def
|
||||||
|
geneweb_util
|
||||||
|
geneweb_gwdb
|
||||||
|
%%%GWDB_PKG%%%
|
||||||
|
%%%SOSA_PKG%%%
|
||||||
|
)
|
||||||
|
(modules)
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(target data.cppo.ml)
|
||||||
|
(deps .depend (:maker mk_data.ml))
|
||||||
|
(action (with-stdout-to %{target} (run ocaml %{maker})))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(target data.ml)
|
||||||
|
(deps data.cppo.ml)
|
||||||
|
(action (run %{bin:cppo} %%%CPPO_D%%% %{deps} -o %{target}))
|
||||||
|
)
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name gwrepl)
|
||||||
|
(public_name gwrepl)
|
||||||
|
(link_flags -linkall -custom)
|
||||||
|
(libraries compiler-libs.toplevel unix)
|
||||||
|
(preprocess
|
||||||
|
(per_module
|
||||||
|
((action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})) gwrepl_exe)
|
||||||
|
((pps ppx_blob) data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(modes byte object)
|
||||||
|
(modules gwrepl data)
|
||||||
|
)
|
62
bin/gwrepl/gwrepl.ml
Normal file
62
bin/gwrepl/gwrepl.ml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
let root = Filename.concat (Filename.get_temp_dir_name ()) ("gwrepl." ^ Data.md5)
|
||||||
|
let path = Filename.concat root
|
||||||
|
|
||||||
|
let mkdir_p ~verbose x =
|
||||||
|
if verbose then print_string ("mkdir: " ^ x ^ "...");
|
||||||
|
let rec loop x =
|
||||||
|
let y = Filename.dirname x in
|
||||||
|
if y <> x && String.length y < String.length x then loop y;
|
||||||
|
try Unix.mkdir x 0o755 with Unix.Unix_error (_, _, _) -> ()
|
||||||
|
in
|
||||||
|
loop x;
|
||||||
|
if verbose then print_endline "OK!"
|
||||||
|
|
||||||
|
let output_file ~verbose (file, contents) =
|
||||||
|
if verbose then print_string ("unpacking: " ^ file ^ "...");
|
||||||
|
let oc = open_out_bin (path file) in
|
||||||
|
output_string oc contents;
|
||||||
|
close_out oc;
|
||||||
|
if verbose then print_endline "OK!"
|
||||||
|
|
||||||
|
let unpack ~force_unpack ~verbose =
|
||||||
|
if force_unpack || not (Sys.file_exists root) then (
|
||||||
|
Array.iter (fun dir -> mkdir_p ~verbose (path dir)) Data.directories;
|
||||||
|
Array.iter (output_file ~verbose) Data.cmas;
|
||||||
|
Array.iter (output_file ~verbose) Data.cmis;
|
||||||
|
Array.iter (output_file ~verbose) Data.shared)
|
||||||
|
|
||||||
|
let run ~ppf ~verbose ~noprompt =
|
||||||
|
Clflags.noversion := true;
|
||||||
|
Clflags.noinit := true;
|
||||||
|
if Array.length Sys.argv <> 1 || noprompt then Clflags.noprompt := true;
|
||||||
|
Array.iter
|
||||||
|
(fun dir ->
|
||||||
|
if verbose then print_endline ("directory: " ^ dir);
|
||||||
|
path dir |> Topdirs.dir_directory)
|
||||||
|
Data.directories;
|
||||||
|
Array.iter
|
||||||
|
(fun (file, _) ->
|
||||||
|
if verbose then print_endline ("load: " ^ file);
|
||||||
|
path file |> Topdirs.dir_load ppf)
|
||||||
|
Data.cmas;
|
||||||
|
Toploop.loop ppf
|
||||||
|
|
||||||
|
(** For script execution, run:
|
||||||
|
cat <script.ml> | [ GWREPL_PPF=/dev/null ] [ GWREPL_VERBOSE=1 ] [ GWREPL_FORCE_UNPACK=1 ] [ GWREPL_NOPROMPT=1 ] gwrepl.exe [scrip_arg1] ...
|
||||||
|
For interactive toplevel, run:
|
||||||
|
gwrepl.exe *)
|
||||||
|
let () =
|
||||||
|
let ppf =
|
||||||
|
match Sys.getenv_opt "GWREPL_PPF" with
|
||||||
|
| None | Some ("STD" | "std") -> Format.std_formatter
|
||||||
|
| Some ("ERR" | "err") -> Format.err_formatter
|
||||||
|
| Some path ->
|
||||||
|
let oc = open_out path in
|
||||||
|
Format.make_formatter (Stdlib.output_substring oc) (fun () ->
|
||||||
|
Stdlib.flush oc)
|
||||||
|
in
|
||||||
|
let verbose = Sys.getenv_opt "GWREPL_VERBOSE" <> None in
|
||||||
|
let force_unpack = Sys.getenv_opt "GWREPL_FORCE_UNPACK" <> None in
|
||||||
|
let noprompt = Sys.getenv_opt "GWREPL_NOPROMPT" <> None in
|
||||||
|
unpack ~force_unpack ~verbose;
|
||||||
|
run ~ppf ~verbose ~noprompt
|
232
bin/gwrepl/mk_data.ml
Normal file
232
bin/gwrepl/mk_data.ml
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
(* This file is used to generate the file 'data.cppo.ml', containing all
|
||||||
|
the files (cmis, cmas, .so) that could be used at runtime by
|
||||||
|
a geneweb interpreter.
|
||||||
|
|
||||||
|
See 'data.mli' for the signature of the generated file. *)
|
||||||
|
|
||||||
|
let read_lines p =
|
||||||
|
let rec loop () =
|
||||||
|
match input_line p with
|
||||||
|
| exception End_of_file ->
|
||||||
|
close_in p;
|
||||||
|
[]
|
||||||
|
| line -> line :: loop ()
|
||||||
|
in
|
||||||
|
loop ()
|
||||||
|
|
||||||
|
module Either = struct
|
||||||
|
type ('a, 'b) t = Left of 'a | Right of 'b
|
||||||
|
end
|
||||||
|
|
||||||
|
let partition_map p l =
|
||||||
|
let rec part left right = function
|
||||||
|
| [] -> (List.rev left, List.rev right)
|
||||||
|
| x :: l -> (
|
||||||
|
match p x with
|
||||||
|
| Some (Either.Left v) -> part (v :: left) right l
|
||||||
|
| Some (Either.Right v) -> part left (v :: right) l
|
||||||
|
| None -> part left right l)
|
||||||
|
in
|
||||||
|
part [] [] l
|
||||||
|
|
||||||
|
let ( // ) = Filename.concat
|
||||||
|
|
||||||
|
let if_sosa_zarith out fn =
|
||||||
|
Printf.fprintf out "\n#ifdef SOSA_ZARITH\n";
|
||||||
|
fn ();
|
||||||
|
Printf.fprintf out "\n#endif\n"
|
||||||
|
|
||||||
|
let before_after_ocaml_version ~before ~after version =
|
||||||
|
(if String.compare Sys.ocaml_version version < 0 then before else after) ()
|
||||||
|
|
||||||
|
let before_after_ocaml_5_1_0 ~before ~after =
|
||||||
|
before_after_ocaml_version "5.1.0" ~before ~after
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let opam_switch_prefix = Sys.getenv "OPAM_SWITCH_PREFIX" in
|
||||||
|
let opam_switch_prefix_lib = opam_switch_prefix // "lib" in
|
||||||
|
let ocaml_stdlib_directory =
|
||||||
|
let output_filename, error_filename =
|
||||||
|
let temporary_filename = Filename.temp_file "gwrepl_" "_ocaml_stdlib" in
|
||||||
|
(temporary_filename ^ ".out", temporary_filename ^ ".err")
|
||||||
|
in
|
||||||
|
let command =
|
||||||
|
let double_quote_if_win32 = if Sys.win32 then "\"" else "" in
|
||||||
|
Printf.sprintf "%sopam exec -- ocamlc -where > %s 2> %s%s"
|
||||||
|
double_quote_if_win32
|
||||||
|
(Filename.quote output_filename)
|
||||||
|
(Filename.quote error_filename)
|
||||||
|
double_quote_if_win32
|
||||||
|
in
|
||||||
|
let exit_code = Sys.command command in
|
||||||
|
if exit_code <> 0 then
|
||||||
|
failwith
|
||||||
|
@@ Printf.sprintf "Command '%s' failed:\nexit code: %d\nerror: %s" command
|
||||||
|
exit_code
|
||||||
|
(String.concat "\n" (read_lines @@ open_in error_filename))
|
||||||
|
else
|
||||||
|
match read_lines @@ open_in output_filename with
|
||||||
|
| ([] | _ :: _ :: _) as lines ->
|
||||||
|
failwith
|
||||||
|
@@ Printf.sprintf "Unexpected output of command '%s':\n%s" command
|
||||||
|
(String.concat "\n" lines)
|
||||||
|
| [ line ] -> line
|
||||||
|
in
|
||||||
|
|
||||||
|
let dune_root, root, (directories0, files0) =
|
||||||
|
let ic = open_in ".depend" in
|
||||||
|
let lines = read_lines ic in
|
||||||
|
let dune_root, out =
|
||||||
|
match lines with
|
||||||
|
| [] -> assert false
|
||||||
|
| dune_root :: out -> (dune_root, out)
|
||||||
|
in
|
||||||
|
let root = dune_root // "_build" // "default" // "lib" in
|
||||||
|
let aux fn =
|
||||||
|
let aux prefix =
|
||||||
|
if
|
||||||
|
String.length fn > String.length prefix
|
||||||
|
&& String.sub fn 0 (String.length prefix) = prefix
|
||||||
|
then
|
||||||
|
Some
|
||||||
|
(String.sub fn (String.length prefix)
|
||||||
|
(String.length fn - String.length prefix))
|
||||||
|
else None
|
||||||
|
in
|
||||||
|
match aux opam_switch_prefix_lib with
|
||||||
|
| Some x -> Some (`opam (opam_switch_prefix_lib, x))
|
||||||
|
| None -> ( match aux root with Some x -> Some (`root x) | None -> None)
|
||||||
|
in
|
||||||
|
( dune_root,
|
||||||
|
root,
|
||||||
|
partition_map
|
||||||
|
(fun s ->
|
||||||
|
try
|
||||||
|
Scanf.sscanf s {|#directory "%[^"]";;|} (fun s ->
|
||||||
|
match aux s with Some s -> Some (Either.Left s) | _ -> None)
|
||||||
|
with _ -> (
|
||||||
|
try
|
||||||
|
Scanf.sscanf s {|#load "%[^"]";;|} (fun s ->
|
||||||
|
match aux s with Some s -> Some (Either.Right s) | _ -> None)
|
||||||
|
with _ -> failwith s))
|
||||||
|
out )
|
||||||
|
in
|
||||||
|
|
||||||
|
let directories =
|
||||||
|
("etc" // "lib" // "ocaml")
|
||||||
|
:: ("etc" // "lib" // "ocaml" // "stublibs")
|
||||||
|
:: List.map
|
||||||
|
(function
|
||||||
|
| `opam (_, d) -> "etc" // "lib" // d
|
||||||
|
| `root d ->
|
||||||
|
"etc" // "lib" // "geneweb"
|
||||||
|
// (d |> Filename.dirname |> Filename.dirname))
|
||||||
|
directories0
|
||||||
|
in
|
||||||
|
let files0 =
|
||||||
|
`opam (Filename.dirname ocaml_stdlib_directory, "ocaml" // "stdlib.cma")
|
||||||
|
:: files0
|
||||||
|
in
|
||||||
|
let cmas, cmis =
|
||||||
|
List.fold_right
|
||||||
|
(fun x (cmas, cmis) ->
|
||||||
|
match x with
|
||||||
|
| `opam (prefix_directory, fn) ->
|
||||||
|
let aux fn = (prefix_directory // fn, "etc" // "lib" // fn) in
|
||||||
|
let cmas = aux fn :: cmas in
|
||||||
|
let ((src, _) as cmi) =
|
||||||
|
aux (Filename.remove_extension fn ^ ".cmi")
|
||||||
|
in
|
||||||
|
let cmis = if Sys.file_exists src then cmi :: cmis else cmis in
|
||||||
|
(cmas, cmis)
|
||||||
|
| `root fn ->
|
||||||
|
let cma = (root // fn, "etc" // "lib" // "geneweb" // fn) in
|
||||||
|
let cmas = cma :: cmas in
|
||||||
|
let dir =
|
||||||
|
dune_root // "_build" // "install" // "default" // "lib"
|
||||||
|
// "geneweb"
|
||||||
|
// Filename.(dirname fn |> basename)
|
||||||
|
in
|
||||||
|
let cmis =
|
||||||
|
Array.fold_left
|
||||||
|
(fun cmis s ->
|
||||||
|
if Filename.check_suffix (Filename.concat dir s) "cmi" then
|
||||||
|
( Filename.concat dir s,
|
||||||
|
"etc" // "lib" // "geneweb"
|
||||||
|
// Filename.concat (Filename.basename dir) s )
|
||||||
|
:: cmis
|
||||||
|
else cmis)
|
||||||
|
cmis
|
||||||
|
(try Sys.readdir dir
|
||||||
|
with exn ->
|
||||||
|
Printf.eprintf "Error in Sys.readdir(%S)\n%!" dir;
|
||||||
|
raise exn)
|
||||||
|
in
|
||||||
|
(cmas, cmis))
|
||||||
|
files0 ([], [])
|
||||||
|
in
|
||||||
|
let cmis =
|
||||||
|
let select =
|
||||||
|
let pref = ocaml_stdlib_directory // "stdlib__" in
|
||||||
|
let len = String.length pref in
|
||||||
|
fun s -> String.length s > len && String.sub s 0 len = pref
|
||||||
|
in
|
||||||
|
Array.fold_left
|
||||||
|
(fun cmis s ->
|
||||||
|
let fname = ocaml_stdlib_directory // s in
|
||||||
|
if Filename.check_suffix fname "cmi" && select fname then
|
||||||
|
(fname, "etc" // "lib" // "ocaml" // s) :: cmis
|
||||||
|
else cmis)
|
||||||
|
cmis
|
||||||
|
(Sys.readdir ocaml_stdlib_directory)
|
||||||
|
in
|
||||||
|
let data = "data.cppo.ml" in
|
||||||
|
let out = open_out_bin data in
|
||||||
|
(let print_dir d = Printf.fprintf out {|"%s";|} d in
|
||||||
|
Printf.fprintf out {|let directories=[||};
|
||||||
|
List.iter print_dir directories;
|
||||||
|
if_sosa_zarith out (fun () -> print_dir ("etc" // "lib" // "stublibs"));
|
||||||
|
Printf.fprintf out {||];;|});
|
||||||
|
(let aux s list =
|
||||||
|
Printf.fprintf out {|let %s=[||} s;
|
||||||
|
List.iter
|
||||||
|
(fun (src, dst) ->
|
||||||
|
Printf.fprintf out {blob|{|%s|},[%%blob {|%s|}];|blob} dst src)
|
||||||
|
list;
|
||||||
|
Printf.fprintf out {||];;|}
|
||||||
|
in
|
||||||
|
aux "cmis" cmis;
|
||||||
|
aux "cmas" cmas);
|
||||||
|
Printf.fprintf out {|let shared=[||};
|
||||||
|
if Sys.unix then (
|
||||||
|
(* FIXME: what is the windows version? *)
|
||||||
|
let aux (prefix_directory, s) =
|
||||||
|
Printf.fprintf out
|
||||||
|
{blob|Filename.(concat "etc" (concat "lib" {|%s|})),[%%blob {|%s|}];|blob}
|
||||||
|
s (prefix_directory // s)
|
||||||
|
in
|
||||||
|
List.iter aux
|
||||||
|
[
|
||||||
|
( Filename.dirname ocaml_stdlib_directory,
|
||||||
|
"ocaml" // "stublibs"
|
||||||
|
// before_after_ocaml_5_1_0
|
||||||
|
~before:(fun () -> "dllcamlstr.so")
|
||||||
|
~after:(fun () -> "dllcamlstrbyt.so") );
|
||||||
|
( Filename.dirname ocaml_stdlib_directory,
|
||||||
|
"ocaml" // "stublibs"
|
||||||
|
// before_after_ocaml_5_1_0
|
||||||
|
~before:(fun () -> "dllunix.so")
|
||||||
|
~after:(fun () -> "dllunixbyt.so") );
|
||||||
|
];
|
||||||
|
if_sosa_zarith out (fun () ->
|
||||||
|
aux (opam_switch_prefix_lib, "stublibs" // "dllzarith.so")));
|
||||||
|
Printf.fprintf out {||];;|};
|
||||||
|
let b = Buffer.create 1024 in
|
||||||
|
let aux =
|
||||||
|
List.iter (fun (src, _) ->
|
||||||
|
Digest.file src |> Digest.to_hex |> Buffer.add_string b)
|
||||||
|
in
|
||||||
|
aux cmis;
|
||||||
|
aux cmas;
|
||||||
|
Printf.fprintf out {|let md5="%s";;|}
|
||||||
|
(Buffer.contents b |> Digest.string |> Digest.to_hex)
|
14
bin/gwu/dune.in
Normal file
14
bin/gwu/dune.in
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(library
|
||||||
|
(name gwu_lib)
|
||||||
|
(public_name geneweb.gwu_lib)
|
||||||
|
(wrapped false)
|
||||||
|
(libraries geneweb gwexport_lib)
|
||||||
|
(modules gwuLib)
|
||||||
|
)
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name gwu)
|
||||||
|
(public_name geneweb.gwu)
|
||||||
|
(modules gwu)
|
||||||
|
(libraries geneweb gwexport_lib gwu_lib str unix %%%GWDB_PKG%%% %%%SOSA_PKG%%%)
|
||||||
|
)
|
68
bin/gwu/gwu.ml
Normal file
68
bin/gwu/gwu.ml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
open GwuLib
|
||||||
|
|
||||||
|
let isolated = ref false
|
||||||
|
|
||||||
|
let speclist opts =
|
||||||
|
( "-odir",
|
||||||
|
Arg.String (fun s -> GwuLib.out_dir := s),
|
||||||
|
"<dir> create files from original name in directory (else on -o file)" )
|
||||||
|
:: ( "-isolated",
|
||||||
|
Arg.Set isolated,
|
||||||
|
" export isolated persons (work only if export all database)." )
|
||||||
|
:: ( "-old_gw",
|
||||||
|
Arg.Set GwuLib.old_gw,
|
||||||
|
" do not export additional fields (for backward compatibility: < 7.00)"
|
||||||
|
)
|
||||||
|
:: ( "-raw",
|
||||||
|
Arg.Set GwuLib.raw_output,
|
||||||
|
" raw output (without possible utf-8 conversion)" )
|
||||||
|
:: ( "-sep",
|
||||||
|
Arg.String (fun s -> GwuLib.separate_list := s :: !GwuLib.separate_list),
|
||||||
|
"<1st_name.num surname> To use together with the option \"-odir\": \
|
||||||
|
separate this person and all his ancestors and descendants sharing the \
|
||||||
|
same surname. All the concerned families are displayed on standard \
|
||||||
|
output instead of their associated files. This option can be used \
|
||||||
|
several times." )
|
||||||
|
:: ( "-sep_only_file",
|
||||||
|
Arg.String (fun s -> GwuLib.only_file := s),
|
||||||
|
"<file> with option \"-sep\", tells to separate only groups of that \
|
||||||
|
file." )
|
||||||
|
:: ( "-sep_limit",
|
||||||
|
Arg.Int (fun i -> GwuLib.sep_limit := i),
|
||||||
|
"<num> When using the option \"-sep\", groups of families can become \
|
||||||
|
isolated in the files. Gwu reconnects them to the separated families \
|
||||||
|
(i.e. displays them to standard output) if the size of these groups is \
|
||||||
|
less than "
|
||||||
|
^ string_of_int !GwuLib.sep_limit
|
||||||
|
^ ". The present option changes this limit." )
|
||||||
|
:: Gwexport.speclist opts
|
||||||
|
|> Arg.align
|
||||||
|
|
||||||
|
let main () =
|
||||||
|
let opts = ref Gwexport.default_opts in
|
||||||
|
Arg.parse (speclist opts) (Gwexport.anonfun opts) Gwexport.errmsg;
|
||||||
|
let opts = !opts in
|
||||||
|
match opts.Gwexport.base with
|
||||||
|
| None -> assert false
|
||||||
|
| Some (ifile, base) ->
|
||||||
|
let select = Gwexport.select opts [] in
|
||||||
|
let in_dir =
|
||||||
|
if Filename.check_suffix ifile ".gwb" then ifile else ifile ^ ".gwb"
|
||||||
|
in
|
||||||
|
let src_oc_ht = Hashtbl.create 1009 in
|
||||||
|
Gwdb.load_ascends_array base;
|
||||||
|
Gwdb.load_strings_array base;
|
||||||
|
if not opts.Gwexport.mem then (
|
||||||
|
Gwdb.load_couples_array base;
|
||||||
|
Gwdb.load_unions_array base;
|
||||||
|
Gwdb.load_descends_array base;
|
||||||
|
());
|
||||||
|
let _ofile, oc, close = opts.Gwexport.oc in
|
||||||
|
if not !GwuLib.raw_output then oc "encoding: utf-8\n";
|
||||||
|
if !GwuLib.old_gw then oc "\n" else oc "gwplus\n\n";
|
||||||
|
GwuLib.prepare_free_occ base;
|
||||||
|
GwuLib.gwu opts !isolated base in_dir !out_dir src_oc_ht select;
|
||||||
|
Hashtbl.iter (fun _ (_, _, close) -> close ()) src_oc_ht;
|
||||||
|
close ()
|
||||||
|
|
||||||
|
let _ = main ()
|
1752
bin/gwu/gwuLib.ml
Normal file
1752
bin/gwu/gwuLib.ml
Normal file
File diff suppressed because it is too large
Load Diff
21
bin/gwu/gwuLib.mli
Normal file
21
bin/gwu/gwuLib.mli
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
val out_dir : string ref
|
||||||
|
val old_gw : bool ref
|
||||||
|
val raw_output : bool ref
|
||||||
|
val separate_list : string list ref
|
||||||
|
val only_file : string ref
|
||||||
|
val sep_limit : int ref
|
||||||
|
|
||||||
|
val prepare_free_occ : ?select:(Gwdb.iper -> bool) -> Gwdb.base -> unit
|
||||||
|
(** Initializes the internal hashtables. Person whose identifier is
|
||||||
|
not selected (`select p = false`) are ignored. *)
|
||||||
|
|
||||||
|
val gwu :
|
||||||
|
Gwexport.gwexport_opts ->
|
||||||
|
bool ->
|
||||||
|
Gwdb.base ->
|
||||||
|
string ->
|
||||||
|
string ->
|
||||||
|
(string, (string -> unit) * bool ref * (unit -> unit)) Hashtbl.t ->
|
||||||
|
(Gwdb.iper -> bool) * (Gwdb.ifam -> bool) ->
|
||||||
|
unit
|
||||||
|
(** Prints the `.gw` file. *)
|
7
bin/setup/dune.in
Normal file
7
bin/setup/dune.in
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
(executable
|
||||||
|
(name setup)
|
||||||
|
(public_name geneweb.setup)
|
||||||
|
(preprocess (action (run %{bin:cppo} %%%CPPO_D%%% %{input-file})))
|
||||||
|
(libraries unix str wserver %%%GWDB_PKG%%% %%%SOSA_PKG%%% geneweb)
|
||||||
|
(modules setup)
|
||||||
|
)
|
9
bin/setup/intro.txt
Normal file
9
bin/setup/intro.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
* Deutsche Version: "de" eingeben
|
||||||
|
* English version: type "en"
|
||||||
|
* Version espanola: escribir en el teclado "es"
|
||||||
|
* Suomalainen versio: kirjoita "fi"
|
||||||
|
* Version francaise: tapez "fr"
|
||||||
|
* Versione italiana: digitate "it"
|
||||||
|
* Latvie<69>u versija: type "lv"
|
||||||
|
* Svensk version: skriv "sv"
|
||||||
|
?
|
45
bin/setup/lang/backg.htm
Normal file
45
bin/setup/lang/backg.htm
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: backg.htm,v 7.00 2018-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Background image]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Background image]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
[To specify a background image for the database "%o", you have to write it:]
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
background="gwd%t{.exe}?m=IM;v=/[foo.jpg]"
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p />
|
||||||
|
|
||||||
|
[replacing "<tt>foo.jpg</tt>" by the real name of your image file.]
|
||||||
|
|
||||||
|
<p />
|
||||||
|
|
||||||
|
<li>
|
||||||
|
[Put the image file in the directory (possibly create it before):]
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
gw%/images
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</ul>
|
39
bin/setup/lang/bsc.htm
Normal file
39
bin/setup/lang/bsc.htm
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi.htm,v 5.1 2006-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
[The operation "%d" will be applied on your database "%a". Warning: it can take some seconds or some minutes, depending on the case. Be patient.]
|
||||||
|
%(
|
||||||
|
The operation "%d" will be applied on your database "%a". Warning: it can take s
|
||||||
|
ome seconds or some minutes, depending on the case. Be patient.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[Push this button to start][:]
|
||||||
|
<p>
|
||||||
|
<form method="post" action="connex_1">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok" /></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ cd "%w"
|
||||||
|
$ %x%/%d%p > comm.log
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
44
bin/setup/lang/bsi.htm
Normal file
44
bin/setup/lang/bsi.htm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi.htm,v 5.1 2006-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
[The operation "%d" will be applied on your database "%a". Warning: it can take some seconds or some minutes, depending on the case. Be patient.]
|
||||||
|
%(
|
||||||
|
The operation "%d" will be applied on your database "%a". Warning: it can take s
|
||||||
|
ome seconds or some minutes, depending on the case. Be patient.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[Push this button to start][:]
|
||||||
|
<p>
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok" /></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ cd "%w"
|
||||||
|
$ %x%/%d%p > comm.log
|
||||||
|
</pre>
|
||||||
|
[<span style="color:#FF0000;">WARNING</span>: The content of file %o will be overwritten.]
|
||||||
|
%(
|
||||||
|
<span style="color:#FF0000;">WARNING</span>: The content of file %o will be over
|
||||||
|
written.
|
||||||
|
%)
|
||||||
|
</body>
|
||||||
|
</html>
|
42
bin/setup/lang/bsi_cache_files.htm
Normal file
42
bin/setup/lang/bsi_cache_files.htm
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2023 - GeneWeb -->
|
||||||
|
<!-- $Id: bsi_cache_files.htm,v 7.10 2023.11.15 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
[applied operation]
|
||||||
|
%(
|
||||||
|
en: The operation "%d" will be applied on your database "%a". Warning: it
|
||||||
|
can take some seconds or some minutes, depending on the case. Be
|
||||||
|
patient.
|
||||||
|
%)
|
||||||
|
|
||||||
|
<p>
|
||||||
|
[click on ok]
|
||||||
|
<p>
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok" /></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[commands]
|
||||||
|
%(
|
||||||
|
en: For information, this operation corresponds to the following commands:
|
||||||
|
%)
|
||||||
|
<pre>
|
||||||
|
$ %x%/%d%S
|
||||||
|
</pre>
|
43
bin/setup/lang/bsi_connex.htm
Normal file
43
bin/setup/lang/bsi_connex.htm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi_connex.htm,v 7.00 2018_04_10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
[The operation "%d" will be applied on your database "%a". Warning: it can take some seconds or some minutes, depending on the case. Be patient.]
|
||||||
|
%(
|
||||||
|
The operation "%d" will be applied on your database "%a". Warning: it can take some
|
||||||
|
seconds or some minutes, depending on the case. Be patient.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[<span style="color:#FF0000;">WARNING</span>: the -del command suppresses irreversibly some families. It may be prudent to have a backup archive.]
|
||||||
|
%(
|
||||||
|
<span style="color:#FF0000;">WARNING</span>: the -del command suppresses irreversibly
|
||||||
|
some families. It may be prudent to have a backup archive.
|
||||||
|
%)
|
||||||
|
<p >
|
||||||
|
[Push this button to start][:]
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok"></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ %x%/%d %Q
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
43
bin/setup/lang/bsi_diff.htm
Normal file
43
bin/setup/lang/bsi_diff.htm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi_diff.htm,v 7.00 2018_04_10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
[The operation "%d" will be applied on your database "%a". Warning: it can take some seconds or some minutes, depending on the case. Be patient.]
|
||||||
|
%(
|
||||||
|
The operation "%d" will be applied on your database "%a". Warning: it can take some
|
||||||
|
seconds or some minutes, depending on the case. Be patient.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[<span style="color:#FF0000;">WARNING</span>: the -del command suppresses irreversibly some families. It may be prudent to have a backup archive.]
|
||||||
|
%(
|
||||||
|
<span style="color:#FF0000;">WARNING</span>: the -del command suppresses irreversibly
|
||||||
|
some families. It may be prudent to have a backup archive.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[Push this button to start][:]
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok"></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ %x%/%d %R > comm.log
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
43
bin/setup/lang/bsi_err.htm
Normal file
43
bin/setup/lang/bsi_err.htm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi_err.htm,v 7.00 2018-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[error]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;"><font color=red>[error]
|
||||||
|
</font></h1>
|
||||||
|
</div>
|
||||||
|
[The command "%d" exited with an error code. This operation may have not been done.]
|
||||||
|
<p>
|
||||||
|
[Here are the traces of the command, maybe you can find an explanation][:]
|
||||||
|
<p>
|
||||||
|
<dl><dt><dd>
|
||||||
|
<pre>
|
||||||
|
%g{- [no traces]
|
||||||
|
-}
|
||||||
|
</pre>
|
||||||
|
</dl>
|
||||||
|
<p>
|
||||||
|
[And the content of gwsetup.log]
|
||||||
|
<p>
|
||||||
|
<dl><dt><dd>
|
||||||
|
<pre>
|
||||||
|
%G{- [no traces]
|
||||||
|
-}
|
||||||
|
</pre>
|
||||||
|
</dl>
|
||||||
|
<p>
|
||||||
|
[Return to the main menu.] (<a href="gwsetup?lang=%l;v=welcome.htm">welcome</a>)
|
||||||
|
</body>
|
||||||
|
</html>
|
44
bin/setup/lang/bsi_fix.htm
Normal file
44
bin/setup/lang/bsi_fix.htm
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bsi_fix.htm,v 7.00 2018_04_10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Application of "%d"]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Application of "%d"]</h1>
|
||||||
|
</div>
|
||||||
|
[The operation "%d" will be applied on your database "%a". Warning: it can take some seconds or some minutes, depending on the case. Be patient.]
|
||||||
|
%(
|
||||||
|
The operation "%d" will be applied on your database "%a". Warning: it can take some
|
||||||
|
seconds or some minutes, depending on the case. Be patient.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[<span style="color:#FF0000;">WARNING</span>: this command modifies the base irreversibly. It may be prudent to have a backup archive.]
|
||||||
|
%(
|
||||||
|
<span style="color:#FF0000;">WARNING</span>: this command modifies the base irreversibly.
|
||||||
|
It may be prudent to have a backup archive.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[Push this button to start][:]
|
||||||
|
<p>
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok" /></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ %x%/%d %p > comm.log
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
63
bin/setup/lang/bso.htm
Normal file
63
bin/setup/lang/bso.htm
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bso.htm,v 7.00 2018-02-25 02:32:19 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Creation of a database]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Creation of a database]</h1>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
%v{<li>
|
||||||
|
[Warning: there already exists a database with the name "%o" in your directory. If you push the button "Ok" below, it will be erased.]
|
||||||
|
%(
|
||||||
|
Warning: there already exists a database with the name "%o" in your directory.
|
||||||
|
If you push the button "Ok" below, it will be erased.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[If you just made this, it is probably its result, and therefore it is not important. Else, return to the previous page and choose another name for your database.]
|
||||||
|
%(
|
||||||
|
If you just made this, it is probably its result, and therefore it is not important.
|
||||||
|
Else, return to the previous page and choose another name for your database.
|
||||||
|
%)
|
||||||
|
<p>}
|
||||||
|
<li>
|
||||||
|
[We are going to create a database named "%o". Remark: this operation can answer in the twinkling of a eye or take some tenths of seconds or some minutes, depending on the cases. Be patient.]
|
||||||
|
%(
|
||||||
|
We are going to create a database named "%o". Remark: this operation can answer
|
||||||
|
in the twinkling of a eye or take some tenths of seconds or some minutes, depend
|
||||||
|
ing on the cases. Be patient.
|
||||||
|
%)
|
||||||
|
<p >
|
||||||
|
[Push the button below to create you database]
|
||||||
|
%v{<br><blink><font color=red>[, and overwrite the previous database "%o" of the target directory]
|
||||||
|
</font></blink>}:
|
||||||
|
<p>
|
||||||
|
<form method="post" action="%d">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd>
|
||||||
|
<input type="submit" value="Ok">
|
||||||
|
<input type="submit" name="cancel" value="[cancel]">
|
||||||
|
</dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ cd "%w"
|
||||||
|
$ %x%/%d%p > comm.log
|
||||||
|
</pre>
|
||||||
|
[This builds a directory named "%o.gwb".]
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
36
bin/setup/lang/bso_comm.htm
Normal file
36
bin/setup/lang/bso_comm.htm
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bso_comm.htm,v 7.00 2018-04-10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Content of comm.log]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Content of comm.log]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p />
|
||||||
|
|
||||||
|
<dl><dt><dd>
|
||||||
|
<pre>
|
||||||
|
%g{- [empty file]
|
||||||
|
-}
|
||||||
|
</pre>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
contenu d'un autre fichier (%o) :
|
||||||
|
|
||||||
|
%H
|
||||||
|
|
||||||
|
done
|
27
bin/setup/lang/bso_err.htm
Normal file
27
bin/setup/lang/bso_err.htm
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bso_err.htm,v 7.00 2018-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[error]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;"><font color=red>[error]
|
||||||
|
</font></h1>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
[The previous command exited with an error code. Your database may have not been created.]
|
||||||
|
<p>
|
||||||
|
[Look at the traces, maybe you can find an explanation.]
|
||||||
|
(<a href="gwsetup?lang=%l;v=traces.htm">traces</a>)
|
||||||
|
<p>
|
||||||
|
[Return to the main menu.] (<a href="gwsetup?lang=%l;v=welcome.htm">welcome</a>)
|
30
bin/setup/lang/bso_log.htm
Normal file
30
bin/setup/lang/bso_log.htm
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bso_log.htm,v 7.00 2018-04-10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Content of result file]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Content of result file]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p />
|
||||||
|
|
||||||
|
<dl><dt><dd>
|
||||||
|
<pre>
|
||||||
|
%H{- [empty file]
|
||||||
|
-}
|
||||||
|
</pre>
|
||||||
|
</dl>
|
36
bin/setup/lang/bso_ok.htm
Normal file
36
bin/setup/lang/bso_ok.htm
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: bso_ok.htm,v 7.00 2018-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Database created]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Database created]</h1>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
[Done. The operation is terminated. Your database named "%o" is created.]
|
||||||
|
<p>
|
||||||
|
[To consult your database, and possibly modify it, the gwd service must have been launched.]
|
||||||
|
<p>
|
||||||
|
[If it is, try the address below. The displayed page is called "welcome page" of your database. Bookmark it.]
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li><a
|
||||||
|
href="http://%m:%P/%o">http://%m:%P/%o</a>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
[Return to the main menu.] (<a href="gwsetup?lang=%l;v=welcome.htm">welcome</a>)
|
||||||
|
<p>
|
||||||
|
[Read the alert messages in the file "comm.log"] (<a href="gwsetup?lang=%l;v=bso_comm.htm">comm.log</a>)
|
||||||
|
</body>
|
||||||
|
</html>
|
123
bin/setup/lang/cache_files.htm
Normal file
123
bin/setup/lang/cache_files.htm
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2023 - GeneWeb -->
|
||||||
|
<!-- $Id: cache_files.htm,v 7.10 2023.11.15 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[cache files]</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[cache files title]
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<form method="get" action="cache_files">
|
||||||
|
<input type=hidden name=opt value=check>
|
||||||
|
<input type="hidden" name="lang" value="%l">
|
||||||
|
|
||||||
|
[select base]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
%b{
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="radio" name="anon" value="%a"> </td>
|
||||||
|
<td><a href="http://%m:%P/%a">%a</a></td>
|
||||||
|
</tr>|
|
||||||
|
<tr align="left"><td>- [no base provided]</tr></td>}
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[select options]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="fn" id="sn" value="on">
|
||||||
|
<label for="fn" style="font-family: monospace">-fn </label>[first_names]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="sn" id="sn" value="on">
|
||||||
|
<label for="sn" style="font-family: monospace">-sn </label>[surnames]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<td><input type="checkbox" name="al" id="al" value="on">
|
||||||
|
<label for="al" style="font-family: monospace">-al </label>[aliases]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<td><input type="checkbox" name="qu" id="qu" value="on">
|
||||||
|
<label for="qu" style="font-family: monospace">-qu </label>[qualifiers]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<td><input type="checkbox" name="pl" id="pl" value="on">
|
||||||
|
<label for="pl" style="font-family: monospace">-pl </label>[places]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<td><input type="checkbox" name="all" id="all" value="on" checked>
|
||||||
|
<label for="all" style="font-family: monospace">-all </label>[all]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="fna" id="fna" value="on">
|
||||||
|
<label for="fna" style="font-family: monospace">-fna </label>[fn alias]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<td><input type="checkbox" name="prog" id="prog" value="on">
|
||||||
|
<label for="prog" style="font-family: monospace">-prog </label>[progress]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[ok]
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<input type="submit" value="Ok">
|
||||||
|
</dl>
|
||||||
|
</form>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
24
bin/setup/lang/cache_files_ok.htm
Normal file
24
bin/setup/lang/cache_files_ok.htm
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2023- GeneWeb -->
|
||||||
|
<!-- $Id: cache_files_ok.htm,v 7.10 2023.11.15 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[cache files compute]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;">
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[cache file compute]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p />
|
||||||
|
[return]
|
||||||
|
|
33
bin/setup/lang/clean_ok.htm
Normal file
33
bin/setup/lang/clean_ok.htm
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: clean_ok.htm,v 5.1 2006-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Operation completed]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Operation completed]</h1>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
[The cleaning up of you database "%a" is completed.]
|
||||||
|
<p>
|
||||||
|
[Your database has been completely rebuilt: the old version is on the subdirectory "old" of the directory "%w". You can recover it in case of problem.]
|
||||||
|
%(
|
||||||
|
Your database has been completely rebuilt: the old version is on the subdirector
|
||||||
|
y "old" of the directory "%w". You can recover it in case of problem.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
[You can consult your very clean new database][:]
|
||||||
|
<p>
|
||||||
|
<ul><li><a href="http://%m:%P/%a">http://%m:%P/%a</a></ul>
|
||||||
|
<p>
|
||||||
|
[Return to the main menu.] (<a href="gwsetup?lang=%l;v=welcome.htm">gesetup</a>)
|
58
bin/setup/lang/cleanup.htm
Normal file
58
bin/setup/lang/cleanup.htm
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: cleanup.htm,v 7.00 2018-04-20 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Cleanup]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Cleaning up a database]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
[If you made many modifications in your database, or if you simply entered much data, it is advised to make a cleaning up, especially if you observe that the access to your database has slowed down.]
|
||||||
|
%(
|
||||||
|
If you made many modifications in your database, or if you simply entered much d
|
||||||
|
ata, it is advised to make a cleaning up, especially if you observe that the acc
|
||||||
|
ess to your database has slowed down.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
<ul><li>
|
||||||
|
[For a simple cleaning up, apply the initialisation of consanguinities.]
|
||||||
|
(<a href="gwsetup?lang=%l;v=consang.htm">consang</a>)
|
||||||
|
<p >
|
||||||
|
<li>
|
||||||
|
<form method="get" action="cleanup">
|
||||||
|
<input type="hidden" name="lang" value="%l" />
|
||||||
|
|
||||||
|
[For a radical cleaning up, select your database by clicking on the associated button][:]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
%b{
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="radio" name="anon" value="%a" /> </td>
|
||||||
|
<td><a href="http://%m:%P/%a">%a</a></td>
|
||||||
|
</tr>|
|
||||||
|
<tr align="left"><td>- [there is no database at present]
|
||||||
|
</tr></td>}
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[Then push this button][:]
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="[Cleanup]
|
||||||
|
" />
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</ul>
|
48
bin/setup/lang/cleanup1.htm
Normal file
48
bin/setup/lang/cleanup1.htm
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: cleanup1.htm,v 7.00 2018-01-01 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Cleanup - Phase 2]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Cleanup]</h1>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
[We are going to proceed to the cleaning up of the database "%a".]
|
||||||
|
<p>
|
||||||
|
[Warning: this operation can take some seconds or minutes, depending on the cases. Be patient.]
|
||||||
|
<p>
|
||||||
|
[Push this button to start][:]
|
||||||
|
<p>
|
||||||
|
<form method="post" action="cleanup_1">
|
||||||
|
%h
|
||||||
|
<dl><dt><dd><input type="submit" value="Ok" /></dl>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
[For information, this operation corresponds to the following commands][:]
|
||||||
|
<pre>
|
||||||
|
$ cd "%w"
|
||||||
|
$ %x%/gwu %a -o tmp.gw
|
||||||
|
$ mkdir old
|
||||||
|
[Under Unix][:]
|
||||||
|
$ rm -rf old/%a.gwb
|
||||||
|
$ mv %a.gwb old/.
|
||||||
|
[Under MSdos][:]
|
||||||
|
$ del old\%a.gwb\*.*
|
||||||
|
$ rmdir old\%a.gwb
|
||||||
|
$ move %a.gwb old\.
|
||||||
|
$ %x%/gwc tmp.gw -nofail -o %a > comm.log
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
147
bin/setup/lang/connex.htm
Normal file
147
bin/setup/lang/connex.htm
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: connex.htm,v 7.00 2018-04-09 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Connex]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Listing connected components]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<form method="get" action="connex">
|
||||||
|
<input type="hidden" name="opt" value="check">
|
||||||
|
<input type="hidden" name="lang" value="%l">
|
||||||
|
<input type="hidden" name="server" value="%m">
|
||||||
|
<input type="hidden" name="gwd_p" value="%P">
|
||||||
|
[Select your database by clicking on the associated button][:]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
%b{
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="radio" name="anon" value="%a"> </td>
|
||||||
|
<td><a href="http://%m:%P/%a">%a</a></td>
|
||||||
|
</tr>|
|
||||||
|
<tr align="left"><td>- [there is no database at present]
|
||||||
|
</tr></td>}
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[Select the options you want][:]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="a" id="a" value="on">
|
||||||
|
<label for="a" style="font-family: monospace">-a </label>[All connex components.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="s" id="s" value="on">
|
||||||
|
<label for="s" style="font-family: monospace">-s </label>[Produce connected components statistics.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<label for="d_1" style="font-family: monospace">-d
|
||||||
|
<input type="input" name="d" size="2" maxlength="2" style="padding-left:4px">
|
||||||
|
</label> [Details for this length.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<label for="i" style="font-family: monospace">-i
|
||||||
|
<input type="input" name="i" size="20" maxlength="50" style="padding-left:4px"></label> [Ignore this file.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="bf" id="bf" value="on">
|
||||||
|
<label for="bf" style="font-family: monospace">-bf </label>[By origin file.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
[<span style="color:#FF0000;">WARNING</span>: The following three options result in irreversible deletions. Having a backup archive is recommended.]
|
||||||
|
%(
|
||||||
|
<span style="color:#FF0000;">WARNING</span>: The following three options result
|
||||||
|
in irreversible deletions. Having a backup archive is recommended.
|
||||||
|
%)
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<label for="del_1" style="font-family: monospace">-del
|
||||||
|
<input type="input" name="del" size="5" maxlength="2" style="padding-left:4px"></label> [Ask for deleting branches whose size <= that value.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<label for="cnt_1" style="font-family: monospace">-cnt
|
||||||
|
<input type="input" name="cnt" size="5" maxlength="2" style="padding-left:4px"></label> [Specifiy the number of branches to be deleted.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="exact" id="exact" value="on">
|
||||||
|
<label for="exact" style="font-family: monospace">-exact </label>[Restrict deleting branches whose size = -del.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="o" id="o" value="choice">
|
||||||
|
<label for="o1" style="font-family: monospace">-o
|
||||||
|
<input type="input" name="o1" size="20" maxlength="50" style="padding-left:4px"></label> [Output results to this file.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<p>
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="radio" name="o" id="o" value="/notes_d/connex.txt">
|
||||||
|
<label for="o" style="font-family: monospace"> </label>
|
||||||
|
[Output results in basename/notes_d/connex.txt (-o must stay empty and notes_d must exist).]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<p>
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="radio" name="o" id="o" value="" checked/>
|
||||||
|
<label for="o" style="font-family: monospace"> </label>[No redirection of results.]
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></dl>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[Then click on this button][:]
|
||||||
|
</li>
|
||||||
|
<input type="submit" value="Ok">
|
||||||
|
</dl>
|
||||||
|
</form>
|
||||||
|
</ul>
|
43
bin/setup/lang/connex_ok.htm
Normal file
43
bin/setup/lang/connex_ok.htm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: connex_ok.htm,v 7.00 2018-04-10 05:35:06 hg Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Connected components identified]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;">
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">
|
||||||
|
[Connected components identified]
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
[You may observe results through two means][:]
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
[By looking at the terminal window if you have not asked for result redirection.]
|
||||||
|
<li>
|
||||||
|
%Io1;;{
|
||||||
|
[Using <b>gwd</b> to visualize the file in the NOTES folder of your base where you have redirected output (%a.gwb/notes_d/connex.txt).<br> This file contains the last set of data stored at this location (which is not necessarily the one you have just computed - see the time stamp at the head of the file).<br> This solution allows you to follow links to designated persons.]
|
||||||
|
(<a href="http://%m:%P/%a?w=w;lang=%l;m=NOTES;f=connex">connex.txt</a>)
|
||||||
|
%(
|
||||||
|
Using <b>gwd</b> to visualize the file in the NOTES folder of your base
|
||||||
|
where you have redirected output (%a.gwb/notes_d/connex.txt).<br>
|
||||||
|
This file contains the last set of data stored at this location
|
||||||
|
(which is not necessarily the one you have just computed -see the
|
||||||
|
time stamp at the head of the file).<br>
|
||||||
|
This solution allows you to follow links to designated persons.
|
||||||
|
%)
|
||||||
|
|
|
||||||
|
[Using <b>gwsetup</b> to visualize the file in which results were redirected ("%K").]
|
||||||
|
(<a href="gwsetup?lang=%l;o=%K;v=bso_log.htm">log</a>)
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
[Return to the main menu.] (<a href="gwsetup?lang=%l;v=welcome.htm">welcome</a>)
|
60
bin/setup/lang/consang.htm
Normal file
60
bin/setup/lang/consang.htm
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="%l">
|
||||||
|
<head>
|
||||||
|
<!-- Copyright (c) 1998-2006 INRIA - GeneWeb -->
|
||||||
|
<!-- $Id: consang.htm,v 7.00 2018-04-20 05:35:06 ddr Exp $ -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="robots" content="none">
|
||||||
|
<link rel="shortcut icon" href="images/favicon_gwsetup.png">
|
||||||
|
|
||||||
|
<title>[Consanguinities]
|
||||||
|
</title>
|
||||||
|
%fsetup.css;
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body %Vbody_prop;>
|
||||||
|
|
||||||
|
<div style="background:url('images/gwlogo.png') no-repeat left top; text-align:center; height:95px; line-height:95px; color:#2f6400;">
|
||||||
|
<h1 style="margin:0;">[Consanguinities]</h1>
|
||||||
|
</div>
|
||||||
|
[The initialization of consanguinities is necessary so that the consanguinities are displayed when browsing the database.]
|
||||||
|
%(
|
||||||
|
The initialization of consanguinities is necessary so that the consanguinities
|
||||||
|
are displayed when browsing the database.
|
||||||
|
%)
|
||||||
|
<p >
|
||||||
|
<form method="get" action="consang">
|
||||||
|
<input type="hidden" name="opt" value="check">
|
||||||
|
<input type="hidden" name="lang" value="%l">
|
||||||
|
<input type="hidden" name="q" value="on">
|
||||||
|
<ul><li>
|
||||||
|
[Select your database by clicking on the associated button][:]
|
||||||
|
<p>
|
||||||
|
<table class="setup">
|
||||||
|
%b{
|
||||||
|
<tr align="left">
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="anon" value="%a"> </td>
|
||||||
|
<td><a href="http://%m:%P/%a">%a</a></td>
|
||||||
|
</tr>|
|
||||||
|
<tr align="left">
|
||||||
|
<td>- [there is no database at present]
|
||||||
|
</tr></td>}
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[Select the options you want][:]
|
||||||
|
<p >
|
||||||
|
<table class="setup">
|
||||||
|
<tr align="left">
|
||||||
|
<td><input type="checkbox" name="scratch" value="on" /> </td>
|
||||||
|
<td>[Restart the computing from scratch.]
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<li>
|
||||||
|
[Then click on this button][:]
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="[Consang]">
|
||||||
|
</ul>
|
||||||
|
</form>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user