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