#!/bin/sh
# ordbanken – oppslag i Norsk ordbank etter ord som tilfredstiller visse kriterium.
#
# Copyright © 2008–2013, 2016, 2018–2020 Karl Ove Hufthammer <karl@huftis.org>.
#
#     This file is part of Ordbanken.
#
#     Ordbanken 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 3 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, see <http://www.gnu.org/licenses/>.

# Nokre nødvendige variablar, samt standardverdiar.
mappe="/usr//share/ordbanken"
fargekod=1   # Fargelegg resultatet.
fargetvang=0 # Men ikkje fargelegg dersom utdata går til eit
             # røyr (med mindre brukaren tvingar det gjennom).
html=0       # Vis tekst og ikkje HTML.
regular=0    # Ikkje bruk regulære uttrykk.
grpord=1     # Grupper ord som standard.
grppara=1    # Grupper bøyingsparadigme som standard.

sprak=$SPRAK_ORDBANKEN
if [ -z "$sprak" ] # Nynorsk som standardspråk viss ikkje noko anna er valt.
then
  sprak=nn
fi

# Versjonsnummer og copyright-år.
versjon='2020-09-10'
copyar='2008–2013, 2016, 2018–2020'

# Namn og e-post til forfattar og adresse for feilrapportar.
adresse_forfattar='Karl Ove Hufthammer <karl@huftis.org>'
adresse_feil='https://savannah.nongnu.org/bugs/?func=additem&group=ordbanken'

# Tekst med info om feilrapportering
tekst_feilrapp="Meld frå om eventuelle feil i programmet på
<$adresse_feil>."

# Sjekk om verktøyet «look» finst.
LOOK_PROG=$(command -v look)
LOOK_FINST=$?

# Tving gawk og dei andre programma til å
# bruka POSIX-modus (gawk treng det for at
# for eksempel søket «[aeiouyæøå]{5}»
# skal verka):
export POSIXLY_CORRECT=1

# Vis informasjon om korleis skriptet skal brukast.
bruk() {
echo 'Bruk: ordbanken [VAL] grunnord [KRITERIUM1] [KRITERIUM2] ...
Slår opp ordet «grunnord» i fullformsordlista til Norsk ordbank,
med eventuell filtrering etter eitt eller fleire kriterium.
'

echo \
'Verdiar for VAL:
  -s, --sprak=SPRÅKKODE	Vel ordliste, der SPRÅKKODE er nn for
   	nynorsk (standard) eller nb for bokmål.
  -e, --eksempel	Vis eksempel på bruk, samt nokre tips.
  -f, --fargekod	Fargekod resultatet (standard).
  -F, --ikkje-fargekod	Ikkje fargekod resultatet.
  -g, --grupper-ord	Grupper oppslaga etter ord (standard).
  -G, --ikkje-grupper-ord	Ikkje grupper oppslaga etter ord.
  -p, --grupper-paradigme	Grupper oppslaga etter bøyingsparadigme (standard).
  -P, --ikkje-grupper-paradigme	Ikkje grupper oppslaga etter bøyingsparadigme.
  -r, --regulært-uttrykk	Oppslagsteksten er eit regulært uttrykk.
      --tekst	Vis resultatet som rein tekst (standard).
      --html	Vis resultatet som HTML.
  -h, --hjelp	Vis denne hjelpeteksten.
  -v, --versjon	Vis programversjon og lisensinformasjon.' | column -t -s"	"

echo ""
echo "$tekst_feilrapp"
}

# Vis nokre eksempel på bruk av skriptet.
versjon() {
echo "Ordbanken versjon $versjon.

Programmet er Copyright © $copyar $adresse_forfattar.
Ordlistene er Copyright © $copyar Universitetet i Bergen og Språkrådet.

Ordbanken er fri programvare, og kjem UTAN NOKON GARANTIAR.
Du må gjerne gje programmet vidare, under visse vilkår.

Lisensvilkår for programmet: GPLv3+ – GNU GPL versjon 3
eller seinare <http://www.gnu.org/licenses/gpl.html>.

Lisensvilkår for ordlistene: CC-BY 4.0
<https://creativecommons.org/licenses/by/4.0/>.

Programmet er skrive er Karl Ove Hufthammer, og
ordlistene vert utvikla og vedlikehaldne av
Universitetet i Bergen og Språkrådet.

$tekst_feilrapp"
}

# Vis nokre eksempel på bruk av skriptet.
eksempel() {
echo 'Her er nokre eksempel på bruk av programmet.
Merk at oppslagsordet må vera fullstendig, men
det held å bruka starten av eventuelle kodar.

Bøying av ordet «å lese» på standardspråket:
  ordbanken lese

Berre perfektum partisipp-former:
  ordbanken lese perf

Ordet «hoppe», men berre som substantiv:
  ordbanken hoppe subst

For verb kan ein velja mellom e- og a-infinitiv:
  ordbanken hoppe
  ordbanken hoppa
Merk at resultata vert litt forskjellige,
då eit oppslag på «hoppa» ikkje vil finna
substantivet «hoppe» (ein hohest), berre
verbet og avleidde adjektivformer.

Bøying av «å finnes» på bokmål:
  ordbanken --sprak=nb finnes

Fleirtal av substantivet «hoppe» på bokmål:
  ordbanken -snb hoppe su fl

Ordet «annan», med fargekoding (som er standard):
  ordbanken --fargekod annan

Same, men no utan fargekoding:
  ordbanken --ikkje-fargekod annan

Same som over, berre mindre å skriva:
  ordbanken -F annan

Lagra resultatet som HTML i fila «annan.html»:
  ordbanken --html annan > annan.html

Ikkje grupper resultata etter ord:
  ordbanken --ikkje-grupper-ord spele
  ordbanken -G spele

Ikkje grupper resultata etter bøyingsparadigme:
  ordbanken --ikkje-grupper-paradigme spele
  ordbanken -P spele

Verken grupper på ord eller bøyingsparadigme:
  ordbanken -GP spele

Viss oppføringa startar med ein bindestrek, må
me bruka «--» for å skilja argument og oppslagsord:
  ordbanken -f -- -aktig


Me kan òg bruka jokerteikn viss me berre kjenner
til delar av ordet (for eksempel ved kryssordløysing).
Jokerteikna er dei same som for Nynorskordboka og
Bokmålsordboka på nett, «%» for null eller fleire
vilkårlege bokstavar, og «_» for éin vilkårleg
bokstav.

Vis alle (grunn)orda som startar på «kr», etterfølgd
av éin vilkårleg bokstav, så bokstavane «ss», så
eventuelt nokre vilkårlege bokstavar, og til slutt
ein «d». Dette finn blant anna ordet «kryssord»:
  ordbanken kr_ss%d

Uttrykk (idiom) der førsteleddet er «på»:
  ordbanken '\''på %'\''

Programmet støttar òg regulære uttrykk, med
kommandolinjevala «--regulært-uttrykk»/«-r».
Desse er mykje kraftigare enn enkle jokerteikn,
men kan vera noko vanskelegare å læra seg.

Dei tre orda «hei», «heim» og «heit»:
  ordbanken --regulært-uttrykk "^hei[mt]?$"

Ord som startar på «dr» og sluttar på «ev»:
  ordbanken -r "^dr.*ev$"

Ord som sluttar på «rama», men ikkje på «drama»:
  ordbanken -r [^d]rama$

Ord der første bokstav er «k», neste er «r»
eller «u», tredje siste er «o» og siste er «d»:
  ordbanken -r "^k[ru].*o.d$"

Bokmålsord med minst 5 etterfølgjande vokalar:
  ordbanken -snb -r "[aeiouyæøå]{5}"


Om ikkje anna er valt, vert nynorsk brukt som
standardspråk, men du kan òg definera standard-
språket i miljøvariabelen SPRAK_ORDBANKEN.

Legg for eksempel
  export SPRAK_ORDBANKEN=nb
til i fila ~/.bashrc for å bruka bokmål som standard.


Programmet støttar òg autofullføring via bash
completion. Viss du har installert og slått
på bash completion, kan du bruka tabulator-
tasten slik:

$ ordbanken [tab]
ordbanken --sprak
(Valet «--sprak» vart automatisk lagt til.
Skjer berre viss SPRAK_ORDBANKEN ikkje
er definert.)

$ ordbanken --sprak [tab]
nb nn
ordbanken --sprak n
(Liste med vala «nb» og «nn» vart vist,
og bokstaven «n» vart lagd til.)

$ ordbanken -[tab]
-e                  --html              -snn
--eksempel          --ikkje-fargekod    --sprak
-f                  -r                  --tekst
--fargekod          --regulært-uttrykk  -v
--hjelp             -snb                --versjon
(Liste over alle moglege argument vart vist.)

$ ordbanken --sprak nn ym[tab]
ym         ymisskap   ymsefinna  ymt
ymis       ymist      ymsen      ymte
ymiskvar   ymje       ymsesidig  ymting
ymisleg    ymse       ymsing 
(Liste over alle nynorskord som startar med «ym» vart vist.)

$ ordbanken --sprak nn hoppe [tab]
adj        fem        m/f        pres-part  verb
appell     fl         nøyt       pret       
bu         imp        perf-part  subst      
eint       inf        pres       ub         
(Liste over alle filtreringskriterium (ordklassar)
ein kan bruka for nynorskordet «hoppe».)

$ ordbanken -snn -- -aktig [tab]
adj   eint  komp  nøyt  sup
bu    fl    m/f   pos   ub
(Det fungerer altså for suffiks òg.)


Du kan sjølvsagt òg bruka eit alias for å spara
nokre tastetrykk når du kallar programmet. Då
må du manuelt setta opp autofullføring til å
fungera med aliaset. Det er heldigvis ganske lett.
Legg for eksempel følgjande i fila «~/.bashrc»:

export SPRAK_ORDBANKEN=nn 
alias o=ordbanken
complete -F _ordbanken o

No treng du berre skriva «o oppslagsord» for å
slå opp eit nynorskord (her ordet «oppslagsord»).
Og skriv du «o oppslag» og trykkjer på tabulator-
tasten, får du forslag på alle nynorskord som
har «oppslag» som førsteledd.'
}

# Hent kommandolinjevala.
val=$(getopt -n "$0" --options="s:ehvfFgGpPr" \
      --longoptions="sprak:,eksempel,hjelp,versjon,fargekod,ikkje-fargekod,grupper-ord,ikkje-grupper-ord,grupper-paradigme,ikkje-grupper-paradigme,regulært-uttrykk,tekst,html" -- "$@")
ret=$?

eval set -- "$val"

# Vis hjelpeteksten og avslutt dersom getopt avslutta med feil.
if [ $ret -ne 0 ]
then
  bruk
  exit 1;
fi

# Tolk kommandolinjevala.
while true; do
  case $1 in
    -h | --hjelp )  bruk; exit 0 ;;
    -v | --versjon )  versjon; exit 0 ;;
    -e | --eksempel )  eksempel; exit 0 ;;
    -f | --fargekod) fargekod=1; fargetvang=1 ;;
    -F | --ikkje-fargekod ) fargekod=0 ;;
    -g | --grupper-ord) grpord=1 ;;
    -G | --ikkje-grupper-ord) grpord=0 ;;
    -p | --grupper-paradigme) grppara=1 ;;
    -P | --ikkje-grupper-paradigme) grppara=0 ;;
    -r | --regulært-uttrykk ) regular=1 ;;
    -s | --sprak ) shift; sprak=$1 ;;
    --tekst ) html=0;;
    --html ) html=1 ;;
    -- ) shift; break ;;
    * ) echo "Feil: Ugyldig argument: $1"; bruk; exit 1;;
  esac
  shift
done

# Ord som skal slåast opp.
ord=$1

# Må ha eit oppslagsord. Avslutt viss me ikkje har det.
if [ -z "$ord" ]
then
  bruk
  exit 1
fi

# Sjekk om språkkoden er gyldig og ev. gjer om til språknamn.
case $sprak in
  nb ) spraknamn="bokmål";;
  nn ) spraknamn="nynorsk";;
  * ) echo "Feil: Språkkoden «$sprak» er ikkje gyldig."; echo "Bruk «nn» (for nynorsk) eller «nb» (for bokmål)."; exit 1;;
esac

# Ordbankfilene ligg i SVN.
ordbok=$mappe/fullform_$sprak.dat


# Støtte for jokerteikn.
# Skriv feilmelding viss det er brukt feil jokerteikn.
if [ $regular = 0 ] && (echo "$ord" | grep -q '[*?]')
then
  echo "Du har brukt feil jokerteikn. Bruk:"
  echo "  % for null eller fleire vilkårlege teikn."
  echo "  _ for eitt vilkårleg teikn."
  exit 1
fi

# Skriv om eventuelle uttrykk med jokerteikn til eit regulært uttrykk.
if [ $regular = 0 ]
then
  if (echo "$ord" | grep -q '[%_]')
  then
    ord="^$(echo "$ord" | sed -e 's/\./\\./g' \
                              -e 's/%/.*/g' \
                              -e 's/_/./g')$" # Byt ut «%», «_» og «.» med høvesvis «.*», «.» og «\.».
    regular=1                                 # Tolk så uttrykket som eit regulært uttrykk.
  fi
fi

# Sjølve utveljinga.
#
# Viss me har eit regulært uttrykk, bruk «gawk» (som er mykje
# tregare enn «look», som me kan bruka elles.
hentOppslag() {
  if [ $regular = 1 ]
  then
    oppslagstekst="$(gawk -F '\t' '{ if ( $1 ~ '/"$1"/') {print $0}}' "$ordbok")"
  elif [ $LOOK_FINST -eq 0 ] # Viss me ikkje har eit regulært uttrykk,
                             # bruk «look» om det finst, og «gawk» elles.
  then
    oppslagstekst="$($LOOK_PROG -- "$1	" "$ordbok")"
  else
    oppslagstekst="$(gawk -F '\t' '{ if ( $1 == '\""$1"\"') {print $0}}' "$ordbok")"
  fi
  echo "$oppslagstekst"
}

# Hent ut oppslaget for ordet
oppslag=$(hentOppslag "$ord")

# For nynorsk, prøv å handtera a-infinitiv, ved å søkja etter 
# same ordet men med a-en til slutt bytt ut med ein e.
if [ "$sprak" = "nn" ]
then
everb="$(echo "$ord" | sed -e 's/a$/e/')"
if [ "$everb" != "$ord" ] && [ $regular = 0 ]
then
  # Hent e-orda (som bør vera verb eller avleidde av verb)
  oppslagVerb=$(hentOppslag "$everb")

  # Hent ut oppføringane der a-versjonen finst som infinitiv
  # av eit verb, og hent så ut ord-ID-ane til desse.
  # (sed-kommandoen er for å hindra problem når ein slår opp
  # ord som inneheld skråstrekar og andre spesialteikn.)
  echo "$oppslagVerb" | gawk '/^$everb	$ord	verb	inf/'
  ordidar=$(echo "$oppslagVerb" | gawk -F'\t' \
            "/^$(echo "$everb" | sed 's!\([]\*\$\/&[]\)!\\\1!g')\t$(echo "$ord" | \
            sed 's!\([]\*\$\/&[]\)!\\\1!g')\tverb\tinf/{print "'"\t"$(NF-1)"\t[^\t]\\+$\n"'";}" \
           | grep -v '^$')

  # Viss det fanst nokon slike ord, legg dei til i søkjeresultata
  if [ "$ordidar" != "" ]
  then
    oppslagVerb=$(echo "$oppslagVerb" | grep "$ordidar")
    oppslag="$oppslag
$oppslagVerb"
  fi
fi
fi


# Forklaring på kommandoane nedanfor:
#  grep: Filtrer oppføringar etter dei opptil seks kriteria.
#        Må passa på at filtreringa først skjer i tredje kolonne,
#        dvs. der sjølve kodane er. Gjer dette ved å sørgja
#        for at det er minst to tabulatorteikn (ein eller
#        annan plass) før skjeteksten.
#  gawk:  Flytt ord-ID og paradigmekode til starten av linje,
#        slik at me kan sortera på dei med «sort» (under).
#  sort: Sorter først etter ord (nyttig ved oppslag på ord som «i»,
#        og ved regulære uttrykk), så ev. etter ord-ID og/eller 
#        paradigmekode og til slutt etter ordklassar (på ein lur måte).
#  gawk:  Legg til eventuelle ordskiljeteikn og paradigmeskiljeteikn.
#  gawk:  Fjern ord-ID-ane og paradigmekodane igjen.
#  sed:  Fjern tabulatorteikn som står igjen først og sist på linja.
#  uniq: Fjern duplikatlinjer som kjem etter kvarandre.
if [ $grpord = 1 ]; then sortering="-k1n,1n"; fi
if [ $grppara = 1 ]; then sortering="$sortering -k2,2"; fi
kolstart="	[^	]\{1,\}	<\{0,1\}"
resultat=$(echo "$oppslag" \
| grep "$kolstart$2" | grep "$kolstart$3" | grep "$kolstart$4" \
| grep "$kolstart$5" | grep "$kolstart$6" | grep "$kolstart$7" \
| gawk -F'\t' 'BEGIN {OFS="\t"; ORS=""} {print $(NF-1), $NF; $(NF-1)=$NF=""; print "\t"$0"\n"}' \
| eval 'sort -k3,3' "$sortering" '-k5,5 -k6,6 -k8,8 -k9,9 -k10,10 -k7,7 -k4,4 -s "-t	"' \
| gawk '{if ($1 != ordid && ordid != "" && "'$grpord'"=="1") {print "==="; } else
          {if ($2 != paradigme && paradigme != "" && "'$grppara'"=="1") {print "---"}};
        ordid=$1; paradigme=$2; print $0 }' \
| gawk -F'\t' 'BEGIN {OFS="\t"} { if ($1 != "===" && $1 != "---") { $1=$2="" }; print $0}' \
| sed 's/^	\+//' | sed 's/	\+$//' \
| uniq)

#| gawk -F'\t' 'BEGIN {OFS="\t"} { if ($1 != "===" && $1 != "---") { $1=$2="" }; print $0}' \

# Skriv til slutt ut resultatet. Anten i HTML-format:
if [ $html = 1 ]
then

# Språkkode brukt til oppslag i ordboka på nett
if [ "$sprak" = "nn" ]
then
  urlsprakkode="nynorsk"
else
  urlsprakkode="bokmaal"
fi

# Lag sjølve tabellen, men lenkjer til nettordbøkene, og med fargekoding.
html=$(echo "$resultat" \
| gawk -F'\t' -v urlsprakkode=$urlsprakkode 'BEGIN { OFS="\t" } {
gsub("<", "\\&lt;", $0)
if ($0=="===")  {print "    </tbody>\n    <tbody>"} else {
  if( $0=="---")  { klasse=klasse" nyttparadigme"; getline }
  linje="      <tr>\n        <td><a href=\"https://ordbok.uib.no/perl/ordbok.cgi?OPP=###"$1"###&amp;"urlsprakkode"=+\">"$1"</a></td>"
  $1=""
  linje=linje$0
  gsub("\t","</td>\n        <td>",linje)
  linje=linje"</td>\n      </tr>"
  if ( $0 ~ "\t.*\t.*nøyt") klasse=klasse" noyt"
  if ( $0 ~ "\t.*\t.*mask") klasse=klasse" mask"
  if ( $0 ~ "\t.*\t.*fem") klasse=klasse" fem"
  if ( $0 ~ "\t.*\t.*m/f") klasse=klasse" mf"
  sub("^ ", "", klasse)
  if ( klasse != "" ) sub("<tr", "<tr class=\""klasse"\"", linje)
  print linje
}
klasse=""
}' | sed -f $mappe/urlkoding.dat)

# HTML-koden før og etter tabellen.
html=$(
echo \
'<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="'"$sprak"'" xml:lang="'"$sprak"'">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Fullformsordliste'" ($spraknamn): $*"'</title>
  <style type="text/css">
    body                 { font-family: sans-serif; }
    table                { border-collapse: collapse; }
    tr:first-child td    { padding-top: 1.5em; }
    tbody:first-child td { padding-top: 0; }
    tr.nyttparadigme     { border-top: 1px dotted silver; }
    td + td              { padding-left: 2em; }'
if [ $fargekod = 1 ] # Eventuelt legg til CSS-kode for fargelegging.
then
echo \
'    body, :link, :visited { color: black; }
    :link, :visited        { font-style: italic; }
    .mask   { text-shadow: 0px 0px 0.1em royalblue; }
    .fem    { text-shadow: 0px 0px 0.1em red; }
    .mf     { text-shadow: 0px 0px 0.1em limegreen; }
    .noyt   { text-shadow: 0px 0px 0.1em darkorange; }'
fi
echo \
'  </style>
</head>

<body>'
if [ -n "$resultat" ] # Ikkje legg til tabell om han er tom.
then
echo '  <table>
    <tbody>'

echo "$html"
echo '    </tbody>
  </table>'
fi
echo \
'</body>

</html>'
)
echo "$html"

else # html = 0, altså tekstvising.
resultat=$(echo "$resultat" \
| column -t -s"	") # Formater som ein fin tabell.

# Rekn ut lengda til den lengeste linja (0-en først
# trengst i tilfelle det ikkje var nokon resultat
linjelengd=0$(echo "$resultat" | gawk ' { if ( length > stlengd ) { stlengd = length } } END{ print stlengd }' )

# Formater ord- og paradigmeskiljeteikna som lange strekar som dekkjer
# heile skjermbreidda.
resultat=$(echo "$resultat" \
| gawk -F'\t' 'BEGIN { OFS="\t"; while (o++<'"$linjelengd"') nyttord=nyttord "═";
             while (p++<'"$linjelengd"') nyttparadigme=nyttparadigme "─"; }
      {if ($1=="===") { print nyttord } else
         { if ($1=="---") { print nyttparadigme } else
           { print $0} }}')

# Eventuell fargekoding. Igjen litt komplisert for å unngå
# at for eksempel grunnordet «fem» (og tilhøyrande bøying)
# skal markerast som hokjønn.

# Sjekk om utdata vert send i eit røyr. Viss ja, berre vis
# fargar viss det er eksplisitt bedt om det.
if [ ! -t 1 ]
then
  if [ $fargetvang = 0 ]
  then
    fargekod=0;
  fi
fi

if [ $fargekod = 1 ]
then
resultat=$(echo "$resultat" \
| sed 's/\(   *[^ ]\{1,\}.*  .*\)\b\(mask\)\b\(.*\)/\1[1;34m\2[0m\3/g' \
| sed 's/\(   *[^ ]\{1,\}.*  .*\)\b\(fem\)\b\(.*\)/\1[1;35m\2[0m\3/g' \
| sed 's/\(   *[^ ]\{1,\}.*  .*\)\b\(m\/f\)\b\(.*\)/\1[1;32m\2[0m\3/g' \
| sed 's/\(   *[^ ]\{1,\}.*  .*\)\b\(nøyt\)\b\(.*\)/\1[1;33m\2[0m\3/g')
fi

# Skriv til slutt ut resultat.
echo "$resultat" | grep -v ^$
fi
