Added RTF version of YAZ doc
[yaz-moved-to-github.git] / doc / yaz.rtf
1 {\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}\r
2 {\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f4\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Times;}\r
3 {\f5\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica;}{\f6\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Courier;}{\f7\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Geneva;}\r
4 {\f8\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Tms Rmn;}{\f9\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helv;}{\f10\froman\fcharset0\fprq2{\*\panose 00000000000000000000}MS Serif;}\r
5 {\f11\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Sans Serif;}{\f12\froman\fcharset0\fprq2{\*\panose 00000000000000000000}New York;}{\f13\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}System;}\r
6 {\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f15\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f16\fnil\fcharset2\fprq2{\*\panose 00000000000000000000}Marlett;}\r
7 {\f17\froman\fcharset0\fprq2{\*\panose 02040602050305030304}Book Antiqua;}{\f18\fswiss\fcharset0\fprq2{\*\panose 020b0502020202020204}Century Gothic;}{\f19\fscript\fcharset0\fprq2{\*\panose 03010101010201010101}Monotype Corsiva;}\r
8 {\f20\froman\fcharset0\fprq2{\*\panose 02040604050505020304}Century Schoolbook;}{\f21\froman\fcharset2\fprq2{\*\panose 05050102010205020202}MT Extra;}{\f22\fdecor\fcharset0\fprq2{\*\panose 04020705040a02060702}Algerian;}\r
9 {\f23\fswiss\fcharset0\fprq2{\*\panose 020f0704030504030204}Arial Rounded MT Bold;}{\f24\fdecor\fcharset0\fprq2{\*\panose 04030b070d0b02020403}Braggadocio;}{\f25\fswiss\fcharset0\fprq2{\*\panose 020b0903060703020204}Britannic Bold;}\r
10 {\f26\fscript\fcharset0\fprq2{\*\panose 03060802040406070304}Brush Script MT;}{\f27\fdecor\fcharset0\fprq2{\*\panose 04020805060202030203}Colonna MT;}{\f28\fdecor\fcharset0\fprq2{\*\panose 04020505020e03040504}Desdemona;}\r
11 {\f29\froman\fcharset0\fprq2{\*\panose 0204060206030a020304}Footlight MT Light;}{\f30\fdecor\fcharset0\fprq2{\*\panose 040307050d0c02020703}Kino MT;}{\f31\froman\fcharset0\fprq2{\*\panose 020a0a07050505020404}Wide Latin;}\r
12 {\f32\fscript\fcharset0\fprq2{\*\panose 03020802060602070202}Matura MT Script Capitals;}{\f33\fdecor\fcharset0\fprq2{\*\panose 040506030a0602020202}Playbill;}{\f34\fscript\fcharset0\fprq2{\*\panose 03010500030000090005}Brush Script;}\r
13 {\f35\fswiss\fcharset0\fprq2{\*\panose 020b0502020104020203}Gill Sans;}{\f36\fmodern\fcharset0\fprq1{\*\panose 02000009000000000000}Letter Gothic;}{\f37\froman\fcharset0\fprq2{\*\panose 02020602050400010903}Perpetua;}\r
14 {\f38\fswiss\fcharset0\fprq2{\*\panose 020e0602050203020203}Lydian;}{\f39\fswiss\fcharset0\fprq2{\*\panose 020b0803020103020203}News Gothic;}{\f40\fswiss\fcharset0\fprq2{\*\panose 020b0606020003020203}News Gothic Condensed;}\r
15 {\f41\froman\fcharset0\fprq2{\*\panose 02040a02080005020203}Photina Casual Black;}{\f42\fswiss\fcharset0\fprq2{\*\panose 020b0506020202030204}Arial Narrow;}{\f43\froman\fcharset0\fprq2{\*\panose 02050604050505020204}Bookman Old Style;}\r
16 {\f44\fnil\fcharset2\fprq2{\*\panose 01010601010101010101}Monotype Sorts;}{\f45\fswiss\fcharset0\fprq2{\*\panose 020b0806030902050204}Impact;}{\f46\fswiss\fcharset0\fprq2{\*\panose 020b0a04020102020204}Arial Black;}\r
17 {\f47\froman\fcharset0\fprq2{\*\panose 02020404030301010803}Garamond;}{\f48\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}AvantGarde;}{\f49\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Bookman;}\r
18 {\f50\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica-Narrow;}{\f51\froman\fcharset0\fprq2{\*\panose 00000000000000000000}NewCenturySchlbk;}{\f52\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Palatino;}\r
19 {\f53\froman\fcharset0\fprq2{\*\panose 00000000000000000000}ZapfChancery;}{\f54\fdecor\fcharset0\fprq2{\*\panose 00000000000000000000}ZapfDingbats;}{\f145\fswiss\fcharset238\fprq2 Tahoma CE;}{\f146\fswiss\fcharset204\fprq2 Tahoma Cyr;}\r
20 {\f148\fswiss\fcharset161\fprq2 Tahoma Greek;}{\f149\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f150\fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f307\fswiss\fcharset238\fprq2 Arial Narrow CE;}{\f308\fswiss\fcharset204\fprq2 Arial Narrow Cyr;}\r
21 {\f310\fswiss\fcharset161\fprq2 Arial Narrow Greek;}{\f311\fswiss\fcharset162\fprq2 Arial Narrow Tur;}{\f312\fswiss\fcharset186\fprq2 Arial Narrow Baltic;}{\f313\froman\fcharset238\fprq2 Bookman Old Style CE;}\r
22 {\f314\froman\fcharset204\fprq2 Bookman Old Style Cyr;}{\f316\froman\fcharset161\fprq2 Bookman Old Style Greek;}{\f317\froman\fcharset162\fprq2 Bookman Old Style Tur;}{\f318\froman\fcharset186\fprq2 Bookman Old Style Baltic;}\r
23 {\f325\fswiss\fcharset238\fprq2 Impact CE;}{\f326\fswiss\fcharset204\fprq2 Impact Cyr;}{\f328\fswiss\fcharset161\fprq2 Impact Greek;}{\f329\fswiss\fcharset162\fprq2 Impact Tur;}{\f330\fswiss\fcharset186\fprq2 Impact Baltic;}\r
24 {\f331\fswiss\fcharset238\fprq2 Arial Black CE;}{\f332\fswiss\fcharset204\fprq2 Arial Black Cyr;}{\f334\fswiss\fcharset161\fprq2 Arial Black Greek;}{\f335\fswiss\fcharset162\fprq2 Arial Black Tur;}{\f336\fswiss\fcharset186\fprq2 Arial Black Baltic;}\r
25 {\f337\froman\fcharset238\fprq2 Garamond CE;}{\f338\froman\fcharset204\fprq2 Garamond Cyr;}{\f340\froman\fcharset161\fprq2 Garamond Greek;}{\f341\froman\fcharset162\fprq2 Garamond Tur;}{\f342\froman\fcharset186\fprq2 Garamond Baltic;}}\r
26 {\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\r
27 \red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 \snext0 Normal;}{\r
28 \s1\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel0\adjustright \b\f1\lang2057 \sbasedon0 \snext0 heading 1;}{\s2\qj\sb240\sa60\keepn\nowidctlpar\adjustright \b\i\f1\lang2057 \sbasedon0 \snext0 heading 2;}{\r
29 \s3\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \f1\fs32\lang2057 \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive Default Paragraph Font;}{\s15\qj\nowidctlpar\adjustright \fs22\lang2057 \sbasedon0 \snext16 Definition Term;}{\r
30 \s16\qj\li360\nowidctlpar\adjustright \fs22\lang2057 \sbasedon0 \snext15 Definition List;}{\*\cs17 \additive \i Definition;}{\s18\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel1\adjustright \b\fs48\lang2057\kerning36 \sbasedon0 \snext0 H1;}{\r
31 \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 \sbasedon0 \snext0 H2;}{\s20\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel3\adjustright \b\fs28\lang2057 \sbasedon0 \snext0 H3;}{\r
32 \s21\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel4\adjustright \b\fs22\lang2057 \sbasedon0 \snext0 H4;}{\s22\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel5\adjustright \b\fs20\lang2057 \sbasedon0 \snext0 H5;}{\r
33 \s23\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel6\adjustright \b\fs16\lang2057 \sbasedon0 \snext0 H6;}{\s24\qj\nowidctlpar\adjustright \i\fs22\lang2057 \sbasedon0 \snext0 Address;}{\s25\qj\li360\ri360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 \r
34 \sbasedon0 \snext25 Blockquote;}{\*\cs26 \additive \i CITE;}{\*\cs27 \additive \f2\fs20 CODE;}{\*\cs28 \additive \i \sbasedon10 Emphasis;}{\*\cs29 \additive \ul\cf2 \sbasedon10 Hyperlink;}{\*\cs30 \additive \ul\cf12 \sbasedon10 FollowedHyperlink;}{\*\r
35 \cs31 \additive \b\f2\fs20 Keyboard;}{\s32\qj\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\tx9590\adjustright \f2\fs20\lang2057 \sbasedon0 \snext32 Preformatted;}{\s33\qc\nowidctlpar\brdrt\brdrdb\brdrw5\brdrcf1 \r
36 \adjustright \v\f1\fs16\lang2057 \snext0 \shidden z-Bottom of Form;}{\s34\qc\nowidctlpar\brdrb\brdrdb\brdrw5\brdrcf1 \adjustright \v\f1\fs16\lang2057 \snext0 \shidden z-Top of Form;}{\*\cs35 \additive \f2 Sample;}{\*\cs36 \additive \b \sbasedon10 Strong;}\r
37 {\*\cs37 \additive \f2\fs20 Typewriter;}{\*\cs38 \additive \i Variable;}{\*\cs39 \additive \v\cf6 HTML Markup;}{\*\cs40 \additive \v Comment;}{\s41\qj\li567\ri567\sb100\sa100\nowidctlpar\brdrt\brdrs\brdrw10\brsp20 \brdrl\brdrs\brdrw10\brsp80 \brdrb\r
38 \brdrs\brdrw10\brsp20 \brdrr\brdrs\brdrw10\brsp80 \adjustright \fs22\lang2057 \sbasedon0 \snext41 Block Text;}{\s42\sb120\sa120\nowidctlpar\adjustright \b\caps\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 1;}{\s43\li220\nowidctlpar\adjustright \r
39 \scaps\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 2;}{\s44\li440\nowidctlpar\adjustright \i\fs20\lang2057 \sbasedon0 \snext0 \sautoupd toc 3;}{\s45\li660\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 4;}{\r
40 \s46\li880\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 5;}{\s47\li1100\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 6;}{\s48\li1320\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd \r
41 toc 7;}{\s49\li1540\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 8;}{\s50\li1760\nowidctlpar\adjustright \fs18\lang2057 \sbasedon0 \snext0 \sautoupd toc 9;}{\s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 \r
42 \sbasedon0 \snext51 Title;}{\s52\qc\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \f1\fs32\lang2057 \sbasedon3 \snext52 Company name;}{\s53\qj\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 \sbasedon0 \snext53 header;}{\r
43 \s54\qj\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 \sbasedon0 \snext54 footer;}{\*\cs55 \additive \sbasedon10 page number;}}{\*\listtable{\list\listtemplateid-1\listsimple{\listlevel\levelnfc0\leveljc0\levelfollow0\r
44 \levelstartat0\levelspace0\levelindent0{\leveltext\'01*;}{\levelnumbers;}}{\listname ;}\listid-2}{\list\listtemplateid134807567\listsimple{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\r
45 \'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1104880785}}{\*\listoverridetable{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\r
46 \levelold\levelspace0\levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls1}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\r
47 \levelspace0\levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls2}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\levelspace0\r
48 \levelindent360{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls3}{\listoverride\listid-2\listoverridecount1{\lfolevel\listoverrideformat{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat0\levelold\levelspace0\levelindent360\r
49 {\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 }}\ls4}{\listoverride\listid1104880785\listoverridecount0\ls5}}{\*\revtbl {Unknown;}}{\info{\title YAZ User's Guide and Reference: Introduction}{\author Sebastian Hammer}{\operator Sebastian Hammer}\r
50 {\creatim\yr1997\mo9\dy17\hr11\min49}{\revtim\yr1997\mo9\dy17\hr14\min14}{\version5}{\edmins26}{\nofpages49}{\nofwords16640}{\nofchars94849}{\*\company Index Data}{\nofcharsws116481}{\vern71}}\r
51 \paperw11906\paperh16838\margl1273\margr1273\margt1417\margb1134 \widowctrl\ftnbj\aenddoc\hyphcaps0\viewkind1\viewscale100 \fet0\sectd \linex0\headery1440\footery1440\colsx709\titlepg\sectdefaultcl {\footer \pard\plain \r
52 \s54\qc\ri360\sb100\sa100\nowidctlpar\tqc\tx4153\tqr\tx8306\adjustright \fs22\lang2057 {\cs55 - }{\field{\*\fldinst {\cs55 PAGE  }}{\fldrslt {\cs55\lang1024 34}}}{\cs55  -}{\cs55\v \'00}{\r
53 \par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}\r
54 {\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\r
55 \pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 {{\*\bkmkstart s1}YAZ User's Guide and Reference\r
56 \r
57 \par }\pard\plain \qc\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {YAZ version 1.4\r
58 \par }\pard\plain \s51\qc\sb100\sa100\nowidctlpar\adjustright \f1\fs48\lang2057 {\fs40 Index Data\r
59 \par }\pard\plain \qc\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
60 \par }\pard\plain \s41\qj\li567\ri567\sb100\sa100\nowidctlpar\brdrt\brdrs\brdrw10\brsp20 \brdrl\brdrs\brdrw10\brsp80 \brdrb\brdrs\brdrw10\brsp20 \brdrr\brdrs\brdrw10\brsp80 \adjustright \fs22\lang2057 {\cs28\i This document is the programmer's guide and re\r
61 ference to the YAZ package. YAZ is a compact toolkit that provides access to the Z39.50/SR protocol, as well as a set of higher-level tools for implementing the server and client roles, respectively. The documentation can be used on its own, or as a refer\r
62 ence when looking at the example applications provided with the package.}{\r
63 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
64 \par }\pard\plain \s44\li440\nowidctlpar\tqr\tldot\tx9350\adjustright \i\fs20\lang2057 {\field\fldedit{\*\fldinst { TOC \\o "1-3" }}{\fldrslt {\lang1024 1. Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132415 \\h }{\lang1024 {\*\datafield \r
65 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310035000000}}}{\fldrslt {\lang1024 2}}}{\lang1024 \r
66 \par 2. Compilation and Installation\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132416 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310036000000}}}{\fldrslt {\r
67 \lang1024 3}}}{\lang1024 \r
68 \par 3. The ASN Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132417 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310037000000}}}{\fldrslt {\lang1024 4}}}{\r
69 \lang1024 \r
70 \par 3.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132418 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310038000000}}}{\fldrslt {\lang1024 4}}}{\r
71 \lang1024 \r
72 \par 3.2 Preparing PDUs\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132419 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400310039000000}}}{\fldrslt {\lang1024 4}}}{\r
73 \lang1024 \r
74 \par 3.3 Object Identifiers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132420 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320030000000}}}{\fldrslt {\lang1024 5}}}{\r
75 \lang1024 \r
76 \par 3.4 EXTERNAL Data\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132421 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320031000000}}}{\fldrslt {\lang1024 6}}}{\r
77 \lang1024 \r
78 \par 3.5 PDU Contents Table\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132422 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320032000000}}}{\fldrslt {\lang1024 7}}}{\r
79 \lang1024 \r
80 \par 4. Supporting Tools\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132423 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320033000000}}}{\fldrslt {\lang1024 11}}}{\r
81 \lang1024 \r
82 \par 4.1 Query Syntax Parsers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132424 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320034000000}}}{\fldrslt {\lang1024 11}\r
83 }}{\lang1024 \r
84 \par 4.2 Object Identifiers\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132425 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320035000000}}}{\fldrslt {\lang1024 16}}}{\r
85 \lang1024 \r
86 \par 4.3 Nibble Memory\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132426 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320036000000}}}{\fldrslt {\lang1024 18}}}{\r
87 \lang1024 \r
88 \par 5. The ODR Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132427 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320037000000}}}{\fldrslt {\lang1024 19}}}{\r
89 \lang1024 \r
90 \par 5.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132428 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320038000000}}}{\fldrslt {\lang1024 19}}}{\r
91 \lang1024 \r
92 \par 5.2 Using ODR\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132429 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400320039000000}}}{\fldrslt {\lang1024 19}}}{\r
93 \lang1024 \r
94 \par 5.3 Programming with ODR\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132430 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330030000000}}}{\fldrslt {\lang1024 24}\r
95 }}{\lang1024 \r
96 \par 5.4 Debugging\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132431 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330031000000}}}{\fldrslt {\lang1024 32}}}{\r
97 \lang1024 \r
98 \par 6. The COMSTACK Module\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132432 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330032000000}}}{\fldrslt {\lang1024 32}}}{\r
99 \lang1024 \r
100 \par 6.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132433 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330033000000}}}{\fldrslt {\lang1024 32}}}{\r
101 \lang1024 \r
102 \par 6.2 Common Functions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132434 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330034000000}}}{\fldrslt {\lang1024 32}}}{\r
103 \lang1024 \r
104 \par 6.3 Client Side\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132435 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330035000000}}}{\fldrslt {\lang1024 34}}}{\r
105 \lang1024 \r
106 \par 6.4 Server Side\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132436 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330036000000}}}{\fldrslt {\lang1024 34}}}{\r
107 \lang1024 \r
108 \par 6.5 Addresses\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132437 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330037000000}}}{\fldrslt {\lang1024 35}}}{\r
109 \lang1024 \r
110 \par 6.6 Diagnostics\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132438 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330038000000}}}{\fldrslt {\lang1024 36}}}{\r
111 \lang1024 \r
112 \par 6.7 Enabling OSI Communication\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132439 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400330039000000}}}{\fldrslt {\r
113 \lang1024 36}}}{\lang1024 \r
114 \par 6.8 Summary and Synopsis\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132440 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340030000000}}}{\fldrslt {\lang1024 38}\r
115 }}{\lang1024 \r
116 \par 7. Making an IR Interface for Your Database with YAZ\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132441 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340031000000\r
117 }}}{\fldrslt {\lang1024 38}}}{\lang1024 \r
118 \par 7.1 Introduction\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132442 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340032000000}}}{\fldrslt {\lang1024 38}}}{\r
119 \lang1024 \r
120 \par 7.2 The Database Frontend\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132443 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340033000000}}}{\fldrslt {\lang1024 39}\r
121 }}{\lang1024 \r
122 \par 7.3 The Backend API\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132444 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340034000000}}}{\fldrslt {\lang1024 39}}}{\r
123 \lang1024 \r
124 \par 7.4 Your main() Routine\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132445 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340035000000}}}{\fldrslt {\lang1024 40}}}\r
125 {\lang1024 \r
126 \par 7.5 The Backend Functions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132446 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340036000000}}}{\fldrslt {\lang1024 41}\r
127 }}{\lang1024 \r
128 \par 7.6 Application Invocation\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132447 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340037000000}}}{\fldrslt {\lang1024 44\r
129 }}}{\lang1024 \r
130 \par 7.7 Summary and Synopsis\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132448 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340038000000}}}{\fldrslt {\lang1024 46}\r
131 }}{\lang1024 \r
132 \par 8. Future Directions\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132449 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400340039000000}}}{\fldrslt {\lang1024 46}}}{\r
133 \lang1024 \r
134 \par 9. License\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132450 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350030000000}}}{\fldrslt {\lang1024 47}}}{\lang1024 \r
135 \r
136 \par 9.1 Index Data Copyright\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132451 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350031000000}}}{\fldrslt {\lang1024 47}\r
137 }}{\lang1024 \r
138 \par 9.2 Additional Copyright Statements\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132452 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350032000000}}}{\fldrslt {\r
139 \lang1024 47}}}{\lang1024 \r
140 \par 10. About Index Data\tab }{\field{\*\fldinst {\lang1024  PAGEREF _Toc399132453 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300390039003100330032003400350033000000}}}{\fldrslt {\lang1024 48}}}{\r
141 \lang1024 \r
142 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 }}\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
143 \par \r
144 \par {\*\bkmkstart _Toc399132415}{\pntext\pard\plain\s19 \b\fs36 \hich\af0\dbch\af0\loch\f0 1.\tab}}\pard\plain \s19\qj\fi-360\li360\sb100\sa100\keepn\nowidctlpar\jclisttab\tx360{\*\pn \pnlvlbody\ilvl0\ls5\pnrnot0\pndec\pnstart1\pnindent360\pnhang{\pntxta .}}\r
145 \ls5\outlinelevel2\adjustright \b\fs36\lang2057 {Introduction{\*\bkmkend s1}{\*\bkmkend _Toc399132415}\r
146 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The }{\i Hacker's Jargon File}{ has the following to say about the use of the prefix "YA" in the name of a software product.\r
147 \par }{\i Yet Another. adj. 1. Of your own work: A humorous allusion often used in titles to acknowledge that the topic is not original, though the content is. As in "Yet A\r
148 nother AI Group" or "Yet Another Simulated Annealing Algorithm". 2. Of others' work: Describes something of which there are already far too many. }{\r
149 \par The }{\b YAZ}{ toolkit offers several different levels of access to the Z39.50 and SR protocols. The level that you need to use depends on your requirements, and the role (server or client) that you want to implement.\r
150 \par The basic level, which is independent of the role, consists of three primary interfaces:\r
151 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b ASN}{\r
152 , which provides a C representation of the Z39.50/SR protocol packages (PDUs). \r
153 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b ODR}{\r
154 , which encodes and decodes the packages according to the BER specification. \r
155 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\b COMSTACK}{\r
156 , which exchanges the encoded packages with a peer process over a network. \r
157 \par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {The ASN module represents the ASN.1 definition of the SR/Z39.50 \r
158 protocol. It establishes a set of type and structure definitions, with one structure for each of the top-level PDUs, and one structure or type for each of the contained ASN.1 types. For primitive types, or other types that are defined by the ASN.1 standar\r
159 d itself (such as the EXTERNAL type), the C representation is provided by the }{\b ODR}{ (Open Data Representation) subsystem.\r
160 \par }{\b ODR}{ is a basic mechanism for representing an ASN.1 type in the C programming language, and for implementing BER encoders and decoders for values of that type. The types defined in the }{\b ASN}{ module generally have the prefix }{\cs27\f2\fs20 Z_}{\r
161 , and a suffix corresponding to the name of the type in the ASN.1 specification of the protocol (generally Z39.50-1995). In the case of base types (those originating in the ASN.1 standard itself), the prefix }{\cs27\f2\fs20 Odr_}{\r
162  is sometimes seen. Either way, look for the actual definition in either }{\cs27\f2\fs20 proto.h}{ (for the types from the protocol), }{\cs27\f2\fs20 odr.h}{ (for the primitive ASN.1 types, or }{\cs27\f2\fs20 odr_use.h}{ (for the ASN.1 }{\i useful}{\r
163  types). The }{\b ASN}{ library also provides functions (which are, in turn, defined using }{\b ODR}{ primitives) for encoding and decoding data values. Their general form is\r
164 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
165 \par int z_xxx(ODR o, Z_xxx **p, int optional);\r
166 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {(note the lower-case "z" in the function name)\r
167 \par }{\i NOTE: If you are using the premade definitions of the }{\b\i ASN}{\i  module, and you are not adding new protocol of your own, the only parts of ODR that you need to worry about are documented in section }{\field{\*\fldinst {\i \r
168 HYPERLINK "yaz-5.html" \\l "odr-use"}{\i\fs20 {\*\datafield \r
169 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000059415a2d352e48544d4c00ffffadde00000000000000000000000000000000000000001a000000140000000300790061007a002d0035002e00680074006d006c00080000006f00640072002d00750073\r
170 00650000000000000000000000}}}{\fldrslt {\cs29\i\ul\cf2 Using ODR}}}{\i .}{\r
171 \par When you have created a BER-encoded buffer, you can use the }{\b COMSTACK}{ subsystem to transmit (or receive) data over the network. The }{\b COMSTACK}{ module provides simple func\r
172 tions for establishing a connection (passively or actively, depending on the role of your application), and for exchanging BER-encoded PDUs over that connection. When you create a connection endpoint, you need to specify what transport to use (OSI or TCP/\r
173 IP), and which protocol you want to use (SR or Z39.50). For the remainer of the connection's lifetime, you don't have to worry about the underlying transport protocol at all - the }{\b COMSTACK}{ will ensure that the correct mechanism is used.\r
174 \par We call the combined interfaces to }{\b ODR}{, }{\b ASN}{, and }{\b COMSTACK}{\r
175  the service level API. It's the API that most closely models the Z39.50/SR service/protocol definition, and it provides unlimited access to all fields and facilities of the protocol definitions.\r
176 \par The reason that the }{\b YAZ}{\r
177  service-level API is a conglomerate of the APIs from three different submodules is twofold. First, we wanted to allow the user a choice of different options for each major task. For instance, if you don't like the protocol API provided by }{\b ODR}{/}{\r
178 \b ASN}{, you can use SNACC or BERUtils instead, and still have the benefits of the transparent transport approach of the }{\b COMSTACK}{\r
179  module. Secondly, we realise that you may have to fit the toolkit into an existing event-processing structure, in a way that is incompatible with the }{\b COMSTACK}{ interface or some other part of }{\b YAZ}{.\r
180 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s2}{\*\bkmkstart _Toc399132416}2. Compilation and Installation{\*\bkmkend s2}{\*\bkmkend _Toc399132416}\r
181 \r
182 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The latest version of the software will generally be found at\r
183 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
184 \par ftp://ftp.indexdata.dk/index/yaz/\r
185 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {If you can't get through to this server, try the mirror site at\r
186 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
187 \par ftp://ftp.funet.fi/pub/doc/library/z3950/yaz/\r
188 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
189 When you unpack the distribution archive, it will create a directory which contains the top-level makefile as well as subdirectories for each of the modules.\r
190 \par Generally, it should be sufficient to run }{\cs27\f2\fs20 make}{\r
191  in this directory. We have tried our best to keep the software portable, and on many platforms, you should be able to compile everything with little or no changes. You may need to update the main makefile to tell the demo applications wher\r
192 e to find the socket library, etc., and in some cases you'll need to jiggle the include files a bit. So far, the software has been ported to the following platforms with little or no difficulties.\r
193 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Unix systems \r
194 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {HP/UX \r
195 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {SunOS/Solaris \r
196 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {DEC Unix \r
197 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Linux \r
198 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {IBM AIX \r
199 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Data General DG/UX (with some CFLAGS tinkering) \r
200 \r
201 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {SGI/IRIX \r
202 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {DDE Supermax \r
203 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Non-unix systems \r
204 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {\r
205 Apple Macintosh (using the Codewarrior programming environment and the GUSI socket libraries) \r
206 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {MS Windows 95/NT (Win32) \r
207 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {IBM AS/400 \r
208 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li1440\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls1\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls1\adjustright {Digital VAX/VMS and AXP/OpenVMS\r
209 \par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {Note that if your system doesn't have a native ANSI C compiler, you may have to acquire one separately. We recommend gcc.\r
210 \par If you move the software to other platforms, we'd be grateful if you'd let us know abou\r
211 t it. If you run into difficulties, we will try to help if we can, and if you solve the problems, we would be happy to include your fixes in the next release. So far, we have mostly avoided #ifdefs for individual platforms, and we'd like to keep it that w\r
212 ay as far as it makes sense.\r
213 \par We maintain a mailing-list for the purpose of announcing new releases and bug-fixes, as well as general discussion. Subscribe by sending mail to }{\cs27\f2\fs20 yaz-request@index.ping.dk}{. General questions and problems can be directed at }{\r
214 \cs27\f2\fs20 yaz-help@index.ping.dk}{, or the address given at the top of this document.\r
215 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {\b0\fs24 {\*\bkmkstart s3}\r
216 \par }{{\*\bkmkstart _Toc399132417}3. The ASN Module{\*\bkmkend s3}{\*\bkmkend _Toc399132417}\r
217 \par {\*\bkmkstart ss3_1}{\*\bkmkstart _Toc399132418}3.1 Introduction{\*\bkmkend ss3_1}{\*\bkmkend _Toc399132418}\r
218 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ASN}{ module provides you with a set of C struct definitions for the various PDUs of\r
219  the protocol, as well as for the complex types appearing within the PDUs. For the primitive data types, the C representation often takes the form of an ordinary C language type, such as }{\cs27\f2\fs20 int}{\r
220 . For ASN.1 constructs that have no direct representation in C, such as general octet strings and bit strings, the }{\b ODR}{ module (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr"}{\fs20 {\*\datafield \r
221 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006400720000000000}}}{\fldrslt {\cs29\ul\cf2 ODR}}}{\r
222 ) provides auxiliary definitions.\r
223 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_2}{\*\bkmkstart _Toc399132419}3.2 Preparing PDUs{\*\bkmkend ss3_2}{\*\bkmkend _Toc399132419}\r
224 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A structure representing a complex ASN.1 type doesn't in itself contain the members of that type. Instead, the structure contains }{\i pointers\r
225 }{ to the members of the type. This is necessary, in part, to allow a mechanism for specifying which of the optional structure (SEQUENCE) members are present, and which are not.\r
226  It follows that you will need to somehow provide space for the individual members of the structure, and set the pointers to refer to the members.\r
227 \par The conversion routines don't care how you allocate and maintain your C structures - they just follow the poi\r
228 nters that you provide. Depending on the complexity of your application, and your personal taste, there are at least three different approaches that you may take when you allocate the structures.\r
229 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
230 You can use static or automatic local variables in the fu\r
231 nction that prepares the PDU. This is a simple approach, and it provides the most efficient form of memory management. While it works well for flat PDUs like the InitReqest, it will generally not be sufficient for say, the generation of an arbitrarily com\r
232 plex RPN query structure. \r
233 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
234 You can individually create the structure and its members using the }{\cs27\f2\fs20 malloc}{(2) function. If you want to ensure that the data is freed when it is no longer needed, you will have to define a function that individually releases eac\r
235 h member of a structure before freeing the structure itself. \r
236 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {You can use the }{\cs27\f2\fs20 odr_malloc()}{\r
237  function (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
238 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
239 { for details). When you use }{\cs27\f2\fs20 odr_malloc()}{, you can release all of the allocated data in a single operation, independent of any pointers and relations between the data. }{\cs27\f2\fs20 odr_malloc()}{\r
240  is based on a "nibble-memory" scheme, in which large portions of memory are allocated, and then gradually handed out with each call to }{\cs27\f2\fs20 odr_malloc()}{. The next time you call }{\cs27\f2\fs20 odr_reset()}{\r
241 , all of the memory allocated since the last call is recycled for future use (actually, it is placed on a free-list). \r
242 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls2\adjustright {\r
243 You can combine all of the methods described here. This will often be the most practical approach. For instance, you might use }{\cs27\f2\fs20 odr_malloc()}{\r
244  to allocate an entire structure and some of its elements, while you leave other elements pointing to global or per-session default variables. \r
245 \par }\pard \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {The }{\b ASN}{ module provides an important aid in creating new PDUs. For each of the PDU types (say, }{\cs27\f2\fs20 Z_InitRequest}{\r
246 ), a function is provided that allocates and initializes an instance of that PDU type for you. In the case of the InitRequest, the function is simply named }{\cs27\f2\fs20 zget_Initrequest()}{\r
247 , and it sets up reasonable default value for all of the mandatory \r
248 members. The optional members are generally initialized to null pointers. This last aspect is very important: it ensures that if the PDU definitions are extended after you finish your implementation (to accommodate new versions of the protocol, say), you \r
249 won't get into trouble with uninitialized pointers in your structures. The functions use }{\cs27\f2\fs20 odr_malloc()}{ to allocate the PDUs and its members, so you can free everything again with a single call to }{\cs27\f2\fs20 odr_reset()}{\r
250 . We strongly recommend that you use the }{\cs27\f2\fs20 zget_*}{ functions whenever you are preparing a PDU (in a C++ API, the }{\cs27\f2\fs20 zget_}{ functions would probably be promoted to constructors for the individual types).\r
251 \par The prototype for the individual PDU types generally look like this:\r
252 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
253 \par Z_<type> *zget_<type>(ODR o);\r
254 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {eg.:\r
255 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
256 \par Z_InitRequest *zget_InitRequest(ODR o);\r
257 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ODR}{ handle should generally be your encoding stream, but it needn't be.\r
258 \par As well as the individual PDU functions, a function }{\cs27\f2\fs20 zget_APDU()}{ is provided, which allocates a toplevel Z-APDU of the type requested:\r
259 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
260 \par Z_APDU *zget_APDU(ODR o, Z_APDU_which which);\r
261 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 which}{ parameter is (of course) the discriminator belonging to the }{\cs27\f2\fs20 Z_APDU}{\r
262  CHOICE type. All of the interface described here is provided by the }{\b ASN}{ module, and you access it through the }{\cs27\f2\fs20 proto.h}{ header file.\r
263 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart oid}{\*\bkmkstart ss3_3}{\*\bkmkstart _Toc399132420}{\*\bkmkend oid}3.3 Object Identifiers\r
264 {\*\bkmkend ss3_3}{\*\bkmkend _Toc399132420}\r
265 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
266 When you refer to object identifiers in your application, you need to be aware that SR and Z39.50 use two different set of OIDs to refer to the same objects. To handle this easily, }{\b YAZ}{ provides a utility module to }{\b ASN}{\r
267  which provides an internal representation of the OIDs used in both protocols. Each oid is described by a structure:\r
268 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
269 \par typedef struct oident\r
270 \par \{\r
271 \par     enum oid_proto proto;\r
272 \par     enum oid_class class;\r
273 \par     enum oid_value value;\r
274 \par     char *desc;\r
275 \par \} oident;\r
276 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 proto}{ field can be set to either }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{. The }{\cs27\f2\fs20 class}{\r
277  might be, say, }{\cs27\f2\fs20 CLASS_RECSYN}{, and the }{\cs27\f2\fs20 value}{ might be }{\cs27\f2\fs20 VAL_USMARC}{ for the USMARC record format. Functions\r
278 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
279 \par Odr_oid *oid_getoidbyent(struct oident *ent);\r
280 \par struct oident *oid_getentbyoid(Odr_oid *o);\r
281 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {are provided to map between object identifiers and database entries. If you store a member of the }{\cs27\f2\fs20 oid_proto}{\r
282  type in your association state information, it's a simple matter, at runtime, to generate the correct OID when you need it\r
283 . For decoding, you can simply ignore the proto field, or if you're strict, you can verify that your peer is using the OID family from the correct protocol. The }{\cs27\f2\fs20 desc}{\r
284  field is a short, human-readable name for the PDU, useful mainly for diagnostic output.\r
285 \par }{\i NO\r
286 TE: Plans are underway to merge the two protocols into a single definition, with one set of object identifiers. When this happens, the oid module will no longer be required to support protocol independence, but it should still be useful as a simple OID da\r
287 tabase.}{\r
288 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_4}{\*\bkmkstart _Toc399132421}3.4 EXTERNAL Data{\*\bkmkend ss3_4}{\*\bkmkend _Toc399132421}\r
289 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
290 In order to achieve extensibility and adaptability to different application domains, the new version of the protocol defines many structures outside of the main ASN.1 specification, referencing t\r
291 hem through ASN.1 EXTERNAL constructs. To simplify the construction and access to the externally referenced data, the }{\b ASN}{ module defines a specialized version of the EXTERNAL construct, called }{\cs27\f2\fs20 Z_External}{. It is defined thus:\r
292 \r
293 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
294 \par typedef struct Z_External\r
295 \par \{\r
296 \par     Odr_oid *direct_reference;\r
297 \par     int *indirect_reference;\r
298 \par     char *descriptor;\r
299 \par     enum\r
300 \par     \{\r
301 \par         /* Generic types */\r
302 \par         Z_External_single = 0,\r
303 \par         Z_External_octet,\r
304 \par         Z_External_arbitrary,\r
305 \par \r
306 \par         /* Specific types */\r
307 \par         Z_External_SUTRS,\r
308 \par         Z_External_explainRecord,\r
309 \par         Z_External_resourceReport1,\r
310 \par         Z_External_resourceReport2\r
311 \par \r
312 \par         ...\r
313 \par \r
314 \par     \} which;\r
315 \par     union\r
316 \par     \{\r
317 \par         /* Generic types */\r
318 \par         Odr_any *single_ASN1_type;\r
319 \par         Odr_oct *octet_aligned;\r
320 \par         Odr_bitmask *arbitrary;\r
321 \par \r
322 \par         /* Specific types */\r
323 \par         Z_SUTRS *sutrs;\r
324 \par         Z_ExplainRecord *explainRecord;\r
325 \par         Z_ResourceReport1 *resourceReport1;\r
326 \par         Z_ResourceReport2 *resourceReport2;\r
327 \par \r
328 \par         ...\r
329 \par \r
330 \par     \} u;\r
331 \par \} Z_External;\r
332 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When decoding, the }{\b ASN}{\r
333  module will attempt to determine which syntax describes the data by looking at the reference fields (currently only the direct-reference). For ASN.1 structured data, you need only consult the }{\cs27\f2\fs20 which}{ field to determine the\r
334  type of data. You can the access the data directly through the union. When constructing data for encoding, you set the union pointer to point to the data, and set the }{\cs27\f2\fs20 which}{\r
335  field accordingly. Remember also to set the direct (or indirect) reference to the correct OID for the data type. For non-ASN.1 data such as MARC records, use the }{\cs27\f2\fs20 octet_aligned}{ arm of the union.\r
336 \par Some servers return ASN.1 structured data values (eg. database records) as BER-encoded records placed in the }{\cs27\f2\fs20 octet-aligned}{ branch of the EXTERNAL CHOICE. The ASN-module will }{\i not}{\r
337  automatically decode these records. To help you decode the records in the application, the function\r
338 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
339 \par Z_ext_typeent *z_ext_gettypebyref(oid_value ref);\r
340 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Can be used to retrieve information about the known, external data type\r
341 s. The function return a pointer to a static area, or NULL, if no match for the given direct reference is found. The }{\cs27\f2\fs20 Z_ext_typeent}{ is defined as:\r
342 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
343 \par typedef struct Z_ext_typeent\r
344 \par \{\r
345 \par     oid_value dref;    /* the direct-reference OID value. */\r
346 \par     int what;          /* discriminator value for the external CHOICE */\r
347 \par     Odr_fun fun;       /* decoder function */\r
348 \par \} Z_ext_typeent;\r
349 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 what}{\r
350  member contains the Z_External union discriminator value for the given type: For the SUTRS record syntax, the value would be }{\cs27\f2\fs20 Z_External_sutrs}{. The }{\cs27\f2\fs20 fun}{\r
351  member contains a pointer to the function which encodes/decodes the given type. Again, for the SUTRS record syntax, the value of }{\cs27\f2\fs20 fun}{ would be }{\cs27\f2\fs20 z_SUTRS}{ (a function pointer).\r
352 \par If you receive an EXTERNAL which contains an octet-string value that you suspect of being an ASN.1-structured data value, you can use }{\cs27\f2\fs20 z_ext_gettypebyref}{\r
353  to look for the provided direct-reference. If the return value is different from NULL, you can use the provided function to decode the BER string (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
354 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
355 {). \r
356 \par If you want to }{\i send}{ EXTERNALs containing ASN.1-structured values in the occtet-aligned branch of the CHOICE, this is possible too. However, on the encoding phase, it requires a somewhat involved juggling around of the various buffers involved.\r
357 \r
358 \par If you need to add new, externally defined data types, you must update the struct above, in the source file }{\cs27\f2\fs20 prt-ext.h}{, as well as the encoder/decoder in the file }{\cs27\f2\fs20 prt-ext.c}{\r
359 . When changing the latter, remember to update both the }{\cs27\f2\fs20 arm}{ arrary and the list }{\cs27\f2\fs20 type_table}{, which drives the CHOICE biasing that is necessary to tell the different, structured types apart on decoding.\r
360 \par }{\i NOTE: Eventually, the EXTERNAL processing will most likely automatically insert the correct OIDs or indire\r
361 ct-refs. First, however, we need to determine how application-context management (specifically the presentation-context-list) should fit into the various modules.}{\r
362 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss3_5}{\*\bkmkstart _Toc399132422}3.5 PDU Contents Table{\*\bkmkend ss3_5}{\*\bkmkend _Toc399132422}\r
363 \r
364 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {We include, for reference, a listing of the fields of each top-level PDU, as well as their default settings.\r
365 \par }\pard\plain \s32\qj\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\r
366 \par Z_InitRequest\r
367 \par -------------\r
368 \par Field                        Type                Default value\r
369 \par \r
370 \par referenceId                  Z_ReferenceId       NULL\r
371 \par protocolVersion              Odr_bitmask         Empty bitmask\r
372 \par options                      Odr_bitmask         Empty bitmask\r
373 \par preferredMessageSize         int                 30*1024\r
374 \par maximumRecordSize            int                 30*1024\r
375 \par idAuthentication             Z_IdAuthentication  NULL\r
376 \par implementationId             char*               "YAZ"\r
377 \par implementationName           char*               "Index Data/YAZ"\r
378 \par implementationVersion        char*               YAZ_VERSION\r
379 \par userInformationField         Z_UserInformation   NULL\r
380 \par otherInfo                    Z_OtherInformation  NULL\r
381 \par \r
382 \par Z_InitResponse\r
383 \par --------------\r
384 \par Field                        Type                Default value\r
385 \par \r
386 \par referenceId                  Z_ReferenceId       NULL\r
387 \par protocolVersion              Odr_bitmask         Empty bitmask\r
388 \par options                      Odr_bitmask         Empty bitmask\r
389 \par preferredMessageSize         int                 30*1024\r
390 \par maximumRecordSize            int                 30*1024\r
391 \par result                       bool_t              TRUE\r
392 \par implementationId             char*               "YAZ"\r
393 \par implementationName           char*               "Index Data/YAZ"\r
394 \par implementationVersion        char*               YAZ_VERSION\r
395 \par userInformationField         Z_UserInformat..    NULL\r
396 \par otherInfo                    Z_OtherInformation  NULL\r
397 \par \r
398 \par Z_SearchRequest\r
399 \par ---------------\r
400 \par Field                        Type                Default value\r
401 \par \r
402 \par referenceId                  Z_ReferenceId       NULL\r
403 \par smallSetUpperBound           int                 0\r
404 \par largeSetLowerBound           int                 1\r
405 \par mediumSetPresentNumber       int                 0\r
406 \par replaceIndicator             bool_t              TRUE\r
407 \par resultSetName                char*               "Default"\r
408 \par num_databaseNames            int                 0\r
409 \par databaseNames                char**              NULL\r
410 \par smallSetElementSetNames      Z_ElementSetNames   NULL\r
411 \par mediumSetElementSetNames     Z_ElementSetNames   NULL\r
412 \par preferredRecordSyntax        Odr_oid             NULL\r
413 \par query                        Z_Query             NULL\r
414 \par additionalSearchInfo         Z_OtherInformation  NULL\r
415 \par otherInfo                    Z_OtherInformation  NULL\r
416 \par \r
417 \par Z_SearchResponse\r
418 \par ----------------\r
419 \par Field                        Type                Default value\r
420 \par \r
421 \par referenceId                  Z_ReferenceId       NULL\r
422 \par resultCount                  int                 0\r
423 \par numberOfRecordsReturned      int                 0\r
424 \par nextResultSetPosition        int                 0\r
425 \par searchStatus                 bool_t              TRUE\r
426 \par resultSetStatus              int                 NULL\r
427 \par presentStatus                int                 NULL\r
428 \par records                      Z_Records           NULL\r
429 \par additionalSearchInfo         Z_OtherInformation  NULL\r
430 \par otherInfo                    Z_OtherInformation  NULL\r
431 \par \r
432 \par Z_PresentRequest\r
433 \par ----------------\r
434 \par Field                        Type                Default value\r
435 \par \r
436 \par referenceId                  Z_ReferenceId       NULL\r
437 \par resultSetId                  char*               "Default"\r
438 \par resultSetStartPoint          int                 1\r
439 \par numberOfRecordsRequested     int                 10\r
440 \par num_ranges                   int                 0\r
441 \par additionalRanges             Z_Range             NULL\r
442 \par recordComposition            Z_RecordComposition NULL\r
443 \par preferredRecordSyntax        Odr_oid             NULL\r
444 \par maxSegmentCount              int                 NULL\r
445 \par maxRecordSize                int                 NULL\r
446 \par maxSegmentSize               int                 NULL\r
447 \par otherInfo                    Z_OtherInformation  NULL\r
448 \par \r
449 \par Z_PresentResponse\r
450 \par -----------------\r
451 \par Field                        Type                Default value\r
452 \par \r
453 \par referenceId                  Z_ReferenceId       NULL\r
454 \par numberOfRecordsReturned      int                 0\r
455 \par nextResultSetPosition        int                 0\r
456 \par presentStatus                int                 Z_PRES_SUCCESS\r
457 \par records                      Z_Records           NULL\r
458 \par otherInfo                    Z_OtherInformation  NULL\r
459 \par \r
460 \par Z_DeleteResultSetRequest\r
461 \par ------------------------\r
462 \par Field                        Type                Default value\r
463 \par \r
464 \par referenceId                  Z_ReferenceId       NULL\r
465 \par deleteFunction               int                 Z_DeleteRequest_list\r
466 \par num_ids                      int                 0\r
467 \par resultSetList                char**              NULL\r
468 \par otherInfo                    Z_OtherInformation  NULL\r
469 \par \r
470 \par Z_DeleteResultSetResponse\r
471 \par -------------------------\r
472 \par Field                        Type                Default value\r
473 \par \r
474 \par referenceId                  Z_ReferenceId       NULL\r
475 \par deleteOperationStatus        int                 Z_DeleteStatus_success\r
476 \par num_statuses                 int                 0\r
477 \par deleteListStatuses           Z_ListStatus**      NULL\r
478 \par numberNotDeleted             int                 NULL\r
479 \par num_bulkStatuses             int                 0\r
480 \par bulkStatuses                 Z_ListStatus        NULL\r
481 \par deleteMessage                char*               NULL\r
482 \par otherInfo                    Z_OtherInformation  NULL\r
483 \par \r
484 \par Z_ScanRequest\r
485 \par -------------\r
486 \par Field                        Type                Default value\r
487 \par \r
488 \par referenceId                  Z_ReferenceId       NULL\r
489 \par num_databaseNames            int                 0\r
490 \par databaseNames                char**              NULL\r
491 \par attributeSet                 Odr_oid             NULL\r
492 \par termListAndStartPoint        Z_AttributesPlus... NULL\r
493 \par stepSize                     int                 NULL\r
494 \par numberOfTermsRequested       int                 20\r
495 \par preferredPositionInResponse  int                 NULL\r
496 \par otherInfo                    Z_OtherInformation  NULL\r
497 \par \r
498 \par Z_ScanResponse\r
499 \par --------------\r
500 \par Field                        Type                Default value\r
501 \par \r
502 \par referenceId                  Z_ReferenceId       NULL\r
503 \par stepSize                     int                 NULL\r
504 \par scanStatus                   int                 Z_Scan_success\r
505 \par numberOfEntriesReturned      int                 0\r
506 \par positionOfTerm               int                 NULL\r
507 \par entries                      Z_ListEntris        NULL\r
508 \par attributeSet                 Odr_oid             NULL\r
509 \par otherInfo                    Z_OtherInformation  NULL\r
510 \par \r
511 \par Z_TriggerResourceControlRequest\r
512 \par -------------------------------\r
513 \par Field                        Type                Default value\r
514 \par \r
515 \par referenceId                  Z_ReferenceId       NULL\r
516 \par requestedAction              int                 Z_TriggerResourceCtrl_resou..\r
517 \par prefResourceReportFormat     Odr_oid             NULL\r
518 \par resultSetWanted              bool_t              NULL\r
519 \par otherInfo                    Z_OtherInformation  NULL\r
520 \par \r
521 \par Z_ResourceControlRequest\r
522 \par ------------------------\r
523 \par Field                        Type                Default value\r
524 \par \r
525 \par referenceId                  Z_ReferenceId       NULL\r
526 \par suspendedFlag                bool_t              NULL\r
527 \par resourceReport               Z_External          NULL\r
528 \par partialResultsAvailable      int                 NULL\r
529 \par responseRequired             bool_t              FALSE\r
530 \par triggeredRequestFlag         bool_t              NULL\r
531 \par otherInfo                    Z_OtherInformation  NULL\r
532 \par \r
533 \par Z_ResourceControlResponse\r
534 \par -------------------------\r
535 \par Field                        Type                Default value\r
536 \par \r
537 \par referenceId                  Z_ReferenceId       NULL\r
538 \par continueFlag                 bool_t              TRUE\r
539 \par resultSetWanted              bool_t              NULL\r
540 \par otherInfo                    Z_OtherInformation  NULL\r
541 \par \r
542 \par Z_AccessControlRequest\r
543 \par ----------------------\r
544 \par Field                        Type                Default value\r
545 \par \r
546 \par referenceId                  Z_ReferenceId       NULL\r
547 \par which                        enum                Z_AccessRequest_simpleForm;\r
548 \par u                            union               NULL\r
549 \par otherInfo                    Z_OtherInformation  NULL\r
550 \par \r
551 \par Z_AccessControlResponse\r
552 \par -----------------------\r
553 \par Field                        Type                Default value\r
554 \par \r
555 \par referenceId                  Z_ReferenceId       NULL\r
556 \par which                        enum                Z_AccessResponse_simpleForm\r
557 \par u                            union               NULL\r
558 \par diagnostic                   Z_DiagRec           NULL\r
559 \par otherInfo                    Z_OtherInformation  NULL\r
560 \par \r
561 \par Z_Segment\r
562 \par ---------\r
563 \par Field                        Type                Default value\r
564 \par \r
565 \par referenceId                  Z_ReferenceId       NULL\r
566 \par numberOfRecordsReturned      int                 value=0\r
567 \par num_segmentRecords           int                 0\r
568 \par segmentRecords               Z_NamePlusRecord    NULL\r
569 \par otherInfo                    Z_OtherInformation  NULL\r
570 \par \r
571 \par Z_Close\r
572 \par -------\r
573 \par Field                        Type                Default value\r
574 \par \r
575 \par referenceId                  Z_ReferenceId       NULL\r
576 \par closeReason                  int                 Z_Close_finished\r
577 \par diagnosticInformation        char*               NULL\r
578 \par resourceReportFormat         Odr_oid             NULL\r
579 \par resourceFormat               Z_External          NULL\r
580 \par otherInfo                    Z_OtherInformation  NULL\r
581 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
582 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s4}{\*\bkmkstart _Toc399132423}4. Supporting Tools{\*\bkmkend s4}{\*\bkmkend _Toc399132423}\r
583 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
584 In support of the service API - primarily the ASN module, which provides the programmatic interface to the Z39.50 APDUs, YAZ contains a collection of tools that support the development of applications.\r
585 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_1}{\*\bkmkstart _Toc399132424}4.1 Query Syntax Parsers{\*\bkmkend ss4_1}{\*\bkmkend _Toc399132424}\r
586 \r
587 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
588 Since the type-1 (RPN) query structure has no direct, useful string representation, every origin application needs to provide some form of mapping from a local query notation or representation to a }{\cs27\f2\fs20 Z_RPNQuery}{\r
589  structure. Some programmers will prefer to construct the query manually, perhaps using }{\cs27\f2\fs20 odr_malloc()}{ to simplify memory management. The YAZ distribution includes two separate, query-generating tools that may be of use to you.\r
590 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Prefix Query Format\r
591 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
592 Since RPN or reverse polish notation is really just a fancy way of describing a suffix notation format (operator follows operands), it would seem that the confusion is total when we now introduce a prefix notation for RPN. The rea\r
593 son is one of simple laziness - it's somewhat simpler to interpret a prefix format, and this utility was designed for maximum simplicity, to provide a baseline representation for use in simple test applications and scripting environments (like Tcl). The d\r
594 emonstration client included with YAZ uses the PQF.\r
595 \par The PQF is defined by the pquery module in the YAZ library. The }{\cs27\f2\fs20 pquery.h}{ file provides the declaration of the functions\r
596 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
597 \par Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf);\r
598 \par \r
599 \par Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,\r
600 \par       Odr_oid **attributeSetP, const char *qbuf);\r
601 \par \r
602 \par int p_query_attset (const char *arg);\r
603 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The function }{\cs27\f2\fs20 p_query_rpn()}{ takes as arguments an }{\b ODR}{ stream (see section }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \r
604 \\l "odr"}{\fs20 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006400720000000000}}}{\fldrslt {\r
605 \cs29\ul\cf2 The ODR Module}}}{) to provide a memory source (the structure created is released on the next call to }{\cs27\f2\fs20 odr_reset()}{ on the stream/), a protocol identifier (one of the constants }{\cs27\f2\fs20 PROTO_Z3950}{ and }{\r
606 \cs27\f2\fs20 PROTO_SR}{), an attribute set reference, and finally a null-terminated string holding the query string.\r
607 \par If the parse went well, }{\cs27\f2\fs20 p_query_rpn()}{ returns a pointer to a }{\cs27\f2\fs20 Z_RPNQuery}{ structure which can be placed directly into a }{\cs27\f2\fs20 Z_SearchRequest}{.\r
608 \par The }{\cs27\f2\fs20 p_query_attset}{ specifies which attribute set to use if the query doesn't specify one by the }{\cs27\f2\fs20 @attrset}{ operator. The }{\cs27\f2\fs20 p_query_attset}{\r
609  returns 0 if the argument is a valid attribute set specifier; otherwise the function returns -1.\r
610 \par The grammar of the PQF is as follows:\r
611 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
612 \par Query ::= [ AttSet ] QueryStruct.\r
613 \par \r
614 \par AttSet ::= string.\r
615 \par \r
616 \par QueryStruct ::= \{ Attribute \} Simple | Complex.\r
617 \par \r
618 \par Attribute ::= '@attr' AttributeType '=' AttributeValue.\r
619 \par \r
620 \par AttributeType ::= integer.\r
621 \par \r
622 \par AttributeValue ::= integer.\r
623 \par \r
624 \par Complex ::= Operator QueryStruct QueryStruct.\r
625 \par \r
626 \par Operator ::= '@and' | '@or' | '@not' | '@prox' Proximity.\r
627 \par \r
628 \par Simple ::= ResultSet | Term.\r
629 \par \r
630 \par ResultSet ::= '@set' string.\r
631 \par \r
632 \par Term ::= string | '"' string '"'.\r
633 \par \r
634 \par Proximity ::= Exclusion Distance Ordered Relation WhichCode UnitCode.\r
635 \par \r
636 \par Exclusion ::= '1' | '0' | 'void'.\r
637 \par \r
638 \par Distance ::= integer.\r
639 \par \r
640 \par Ordered ::= '1' | '0'.\r
641 \par \r
642 \par Relation ::= integer.\r
643 \par \r
644 \par WhichCode ::= 'known' | 'private' | integer.\r
645 \par \r
646 \par UnitCode ::= integer.\r
647 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You will note that the syntax above is a fairly faithful representation of RPN, except for the }{\cs27\f2\fs20 Attibute}{\r
648 , which has been moved a step away from the term, allowing you to associate one or more attributes with an entire query structure. The parser will automatically apply the given attributes to each term as required.\r
649 \par The following are all examples of valid queries in the PQF.\r
650 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
651 \par dylan\r
652 \par \r
653 \par "bob dylan"\r
654 \par \r
655 \par @or "dylan" "zimmerman"\r
656 \par \r
657 \par @set Result-1\r
658 \par \r
659 \par @or @and bob dylan @set Result-1\r
660 \par \r
661 \par @attr 4=1 @and @attr 1=1 "bob dylan" @attr 1=4 "slow train coming"\r
662 \par \r
663 \par @attr 4=1 @attr 1=4 "self portrait"\r
664 \par \r
665 \par @prox 0 3 1 2 k 2 dylan zimmerman\r
666 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Common Command Language\r
667 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
668 Not all users enjoy typing in prefix query structures and numerical attribute values, even in a minimalistic test client. In the library world, the more intuitive Common Command Language (or ISO 8777) has enjoyed some popularity - especially before the wi\r
669 despread availability of graphical interfaces. It is still useful in applications where you for some reason or other need to provide a symbolic language for expressing boolean query structures.\r
670 \par The EUROPAGATE research project working under the Libraries pro\r
671 gramme of the European Commission's DG XIII has, amongst other useful tools, implemented a general-purpose CCL parser which produces an output structure that can be trivially converted to the internal RPN representation of YAZ (The }{\cs27\f2\fs20 \r
672 Z_RPNQuery}{ structure). Since the CCL utility - along with the rest of the software produced by EUROPAGATE - is made freely available on a liberal license, it is included as a supplement to YAZ.\r
673 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL Syntax\r
674 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The CCL parser obeys the following grammar for the FIND argument. The syntax is annotated by in the lines prefixed by }{\cs27\f2\fs20 --}{.\r
675 \r
676 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
677 \par CCL-Find ::= CCL-Find Op Elements\r
678 \par            | Elements.\r
679 \par \r
680 \par Op ::= "and" | "or" | "not"\r
681 \par -- The above means that Elements are separated by boolean operators.\r
682 \par \r
683 \par Elements ::= '(' CCL-Find ')'\r
684 \par            | Set\r
685 \par            | Terms\r
686 \par            | Qualifiers Relation Terms\r
687 \par            | Qualifiers Relation '(' CCL-Find ')'\r
688 \par            | Qualifiers '=' string '-' string\r
689 \par -- Elements is either a recursive definition, a result set reference, a\r
690 \par -- list of terms, qualifiers followed by terms, qualifiers followed\r
691 \par -- by a recursive definition or qualifiers in a range (lower - upper).\r
692 \par \r
693 \par Set ::= 'set' = string\r
694 \par -- Reference to a result set\r
695 \par \r
696 \par Terms ::= Terms Prox Term\r
697 \par         | Term\r
698 \par -- Proximity of terms.\r
699 \par \r
700 \par Term ::= Term string\r
701 \par        | string\r
702 \par -- This basically means that a term may include a blank\r
703 \par \r
704 \par Qualifiers ::= Qualifiers ',' string\r
705 \par              | string\r
706 \par -- Qualifiers is a list of strings separated by comma\r
707 \par \r
708 \par Relation ::= '=' | '>=' | '<=' | '<>' | '>' | '<'\r
709 \par -- Relational operators. This really doesn't follow the ISO8777\r
710 \par -- standard.\r
711 \par \r
712 \par Prox ::= '%' | '!'\r
713 \par -- Proximity operator\r
714 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The following queries are all valid:\r
715 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
716 \par dylan\r
717 \par \r
718 \par "bob dylan"\r
719 \par \r
720 \par dylan or zimmerman\r
721 \par \r
722 \par set=1\r
723 \par \r
724 \par (dylan and bob) or set=1\r
725 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assuming that the qualifiers }{\cs27\f2\fs20 ti}{, }{\cs27\f2\fs20 au}{ and }{\cs27\f2\fs20 date}{ are defined we may use: \r
726 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
727 \par ti=self portrait\r
728 \par \r
729 \par au=(bob dylan and slow train coming)\r
730 \par \r
731 \par date>1980 and (ti=((self portrait)))\r
732 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL Qualifiers\r
733 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
734 Qualifiers are used to direct the search to a particular searchable index, such as title (ti) and author indexes (au). The CCL standard itself doesn't specify a particular set of qualifiers, but it does suggest a few short-hand notations. You can customiz\r
735 e\r
736  the CCL parser to support a particular set of qualifiers to relect the current target profile. Traditionally, a qualifier would map to a particular use-attribute within the BIB-1 attribute set. However, you could also define qualifiers that would set, fo\r
737 r example, the structure-attribute.\r
738 \par Consider a scenario where the target support ranked searches in the title-index. In this case, the user could specify \r
739 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
740 \par ti,ranked=knuth computer\r
741 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {and the }{\cs27\f2\fs20 ranked}{ would map to structure=free-form-text (4=105) and the }{\cs27\f2\fs20 ti}{ would map to title (1=4).\r
742 \par A "profile" with a set predefined CCL qualifiers can be read from a file. The YAZ client reads its CCL qualifiers from a file named }{\cs27\f2\fs20 default.bib}{. Each line in the file has the form:\r
743 \par }{\i qualifier-name}{ }{\i type}{=}{\i val}{ }{\i type}{=}{\i val}{ ...\r
744 \par where }{\i qualifier-name}{ is the name of the qualifier to be used (eg. }{\cs27\f2\fs20 ti}{), }{\i type}{ is a BIB-1 category type and }{\i val}{ is the corresponding BIB-1 attribute value. The }{\i type}{ can be either numeric or it may be either }{\r
745 \cs27\f2\fs20 u}{ (use), }{\cs27\f2\fs20 r}{ (relation), }{\cs27\f2\fs20 p}{ (position), }{\cs27\f2\fs20 s}{ (structure), }{\cs27\f2\fs20 t}{ (truncation) or }{\cs27\f2\fs20 c}{ (completeness). The }{\i qualifier-name}{ }{\cs27\f2\fs20 term}{\r
746  has a special meaning. The types and values for this definition is used when }{\i no}{ qualifier is present.\r
747 \par Consider the following definition: \r
748 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
749 \par ti       u=4 s=1\r
750 \par au       u=1 s=1\r
751 \par term     s=105\r
752 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Two qualifiers are defined, }{\cs27\f2\fs20 ti}{ and }{\cs27\f2\fs20 au}{. They both set the structure-attribute to phrase (1). }{\r
753 \cs27\f2\fs20 ti}{ sets the use-attribute to 4. }{\cs27\f2\fs20 au}{ sets the use-attribute to 1. When no qualifiers are used in the query the structure-attribute is set to free-form-text (105).\r
754 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CCL API\r
755 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {All public definitions can be found in the header file }{\cs27\f2\fs20 ccl.h}{. A profile identifier is of type }{\cs27\f2\fs20 CCL_bibset}{\r
756 . A profile must be created with the call to the function }{\cs27\f2\fs20 ccl_qual_mk}{ which returns a profile handle of type }{\cs27\f2\fs20 CCL_bibset}{.\r
757 \par To read a file containing qualifier definitions the function }{\cs27\f2\fs20 ccl_qual_file}{ may be convenient. This function takes an already opened }{\cs27\f2\fs20 FILE}{ handle pointer as argument along with a }{\cs27\f2\fs20 CCL_bibset}{ handle.\r
758 \r
759 \par To parse a simple string with a FIND query use the function \r
760 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
761 \par struct ccl_rpn_node *ccl_find_str (CCL_bibset bibset, const char *str,\r
762 \par                                    int *error, int *pos);\r
763 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which takes the CCL profile (}{\cs27\f2\fs20 bibset}{) and query (}{\cs27\f2\fs20 str}{\r
764 ) as input. Upon successful completion the RPN tree is returned. If an error eccur, such as a syntax error, the integer pointed to by }{\cs27\f2\fs20 error}{ holds the error code and }{\cs27\f2\fs20 pos}{\r
765  holds the offset inside query string in which the parsing failed.\r
766 \par An english representation of the error may be obtained by calling the }{\cs27\f2\fs20 ccl_err_msg}{ function. The error codes are listed in }{\cs27\f2\fs20 ccl.h}{.\r
767 \par To convert the CCL RPN tree (type }{\cs27\f2\fs20 struct ccl_rpn_node *}{) to the Z_RPNQuery of YAZ the function }{\cs27\f2\fs20 ccl_rpn_query}{ must be used. This function which is part of YAZ is implemented in }{\cs27\f2\fs20 yaz-ccl.c}{\r
768 . After calling this function the CCL RPN tree is probably no longer needed. The }{\cs27\f2\fs20 ccl_rpn_delete}{ destroys the CCL RPN tree.\r
769 \par A CCL profile may be destroyed by calling the }{\cs27\f2\fs20 ccl_qual_rm}{ function.\r
770 \par The token names for the CCL operators may be changed by setting the globals (all type }{\cs27\f2\fs20 char *}{) }{\cs27\f2\fs20 ccl_token_and}{, }{\cs27\f2\fs20 ccl_token_or}{, }{\cs27\f2\fs20 ccl_token_not}{ and }{\cs27\f2\fs20 ccl_token_set}{\r
771 . An operator may have aliases, i.e. there may be more than one name for the operator. To do this, separate each alias with a space character.\r
772 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_2}{\*\bkmkstart _Toc399132425}4.2 Object Identifiers{\*\bkmkend ss4_2}{\*\bkmkend _Toc399132425}\r
773 \r
774 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The basic YAZ representation of an OID is an array of integers, terminated with the value -1. The }{\b ODR}{\r
775  module provides two utility-functions to create and copy this type of data elements:\r
776 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
777 \par Odr_oid *odr_getoidbystr(ODR o, char *str);\r
778 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates an OID based on a string-based representation using dots (.) to separate elements in the OID.\r
779 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
780 \par Odr_oid *odr_oiddup(ODR odr, Odr_oid *o);\r
781 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates a copy of the OID referenced by the }{\i o}{ parameter. Both functions take an }{\b ODR}{\r
782  stream as parameter. This stream is used to allocate memory for the data elements, which is released on a subsequent call to }{\cs27\f2\fs20 odr_reset()}{ on that stream.\r
783 \par The }{\b OID}{ module provides a higher-level representation of the family of object identifers which describe the Z39.50 protocol and its related objects. The definition of the module interface is given in the }{\cs27\f2\fs20 oid.h}{ file.\r
784 \par The interface is mainly based on the }{\cs27\f2\fs20 oident}{ structure. The definition of this structure looks like this:\r
785 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
786 \par typedef struct oident\r
787 \par \{\r
788 \par     oid_proto proto;\r
789 \par     oid_class oclass;\r
790 \par     oid_value value;\r
791 \par     int oidsuffix[20];\r
792 \par     char *desc;\r
793 \par \} oident;\r
794 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\i proto}{ field takes one of the values\r
795 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
796 \par PROTO_Z3950\r
797 \par PROTO_SR\r
798 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
799 If you don't care about talking to SR-based implementations (few exist, and they may become fewer still if and when the ISO SR and ANSI Z39.50 documents are merged into a single standard), you can ignore this field on incoming packages, and always set it \r
800 to PROTO_Z3950 for outgoing packages.\r
801 \par The }{\i oclass}{ field takes one of the values\r
802 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
803 \par CLASS_APPCTX\r
804 \par CLASS_ABSYN\r
805 \par CLASS_ATTSET\r
806 \par CLASS_TRANSYN\r
807 \par CLASS_DIAGSET\r
808 \par CLASS_RECSYN\r
809 \par CLASS_RESFORM\r
810 \par CLASS_ACCFORM\r
811 \par CLASS_EXTSERV\r
812 \par CLASS_USERINFO\r
813 \par CLASS_ELEMSPEC\r
814 \par CLASS_VARSET\r
815 \par CLASS_SCHEMA\r
816 \par CLASS_TAGSET\r
817 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {corresponding to the OID classes defined by the Z39.50 standard.\r
818 \par Finally, the }{\i value}{ field takes one of the values\r
819 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
820 \par VAL_APDU\r
821 \par VAL_BER\r
822 \par VAL_BASIC_CTX\r
823 \par VAL_BIB1\r
824 \par VAL_EXP1\r
825 \par VAL_EXT1\r
826 \par VAL_CCL1\r
827 \par VAL_GILS\r
828 \par VAL_WAIS\r
829 \par VAL_STAS\r
830 \par VAL_DIAG1\r
831 \par VAL_ISO2709\r
832 \par VAL_UNIMARC\r
833 \par VAL_INTERMARC\r
834 \par VAL_CCF\r
835 \par VAL_USMARC\r
836 \par VAL_UKMARC\r
837 \par VAL_NORMARC\r
838 \par VAL_LIBRISMARC\r
839 \par VAL_DANMARC\r
840 \par VAL_FINMARC\r
841 \par VAL_MAB\r
842 \par VAL_CANMARC\r
843 \par VAL_SBN\r
844 \par VAL_PICAMARC\r
845 \par VAL_AUSMARC\r
846 \par VAL_IBERMARC\r
847 \par VAL_EXPLAIN\r
848 \par VAL_SUTRS\r
849 \par VAL_OPAC\r
850 \par VAL_SUMMARY\r
851 \par VAL_GRS0\r
852 \par VAL_GRS1\r
853 \par VAL_EXTENDED\r
854 \par VAL_RESOURCE1\r
855 \par VAL_RESOURCE2\r
856 \par VAL_PROMPT1\r
857 \par VAL_DES1\r
858 \par VAL_KRB1\r
859 \par VAL_PRESSET\r
860 \par VAL_PQUERY\r
861 \par VAL_PCQUERY\r
862 \par VAL_ITEMORDER\r
863 \par VAL_DBUPDATE\r
864 \par VAL_EXPORTSPEC\r
865 \par VAL_EXPORTINV\r
866 \par VAL_NONE\r
867 \par VAL_SETM\r
868 \par VAL_SETG\r
869 \par VAL_VAR1\r
870 \par VAL_ESPEC1\r
871 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {again, corresponding to the specific OIDs defined by the standard.\r
872 \par The }{\i desc}{ field contains a brief, mnemonic name for the OID in question.\r
873 \par The function\r
874 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
875 \par struct oident *oid_getentbyoid(int *o);\r
876 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {takes as argument an OID, and returns a pointer to a static area containing an }{\cs27\f2\fs20 oident}{\r
877  structure. You typically use this function when you receive a PDU containing an OID, and you wish to branch out depending on the specific OID value.\r
878 \par The function\r
879 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
880 \par int *oid_getoidbyent(struct oident *ent);\r
881 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Takes as argument an }{\cs27\f2\fs20 oident}{ structure - in which the }{\i proto}{, }{\i oclass}{, and }{\i value}{\r
882  fields are assumed to be set correctly - and returns a pointer to a static buffer containing the base representation of the corresponding OID. The buffer is overwritten on the next successive call to the function, so if you need to create more than one O\r
883 ID in this fashiion, you should use }{\cs27\f2\fs20 odr_oiddup()}{ or some similar measure to create a copy of the OID.\r
884 \par The }{\cs27\f2\fs20 oid_getoidbyent()}{ function can be used whenever you need to prepare a PDU containing one or more OIDs. The separation of the }{\i protocol}{ element from the \r
885 remainer of the OID-description makes it simple to write applications that can communicate with either Z39.50 or OSI SR-based applications.\r
886 \par The function\r
887 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
888 \par oid_value oid_getvalbyname(const char *name);\r
889 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {takes as argument a mnemonic OID name, and returns the }{\i value}{\r
890  field of the first entry in the database that contains the given name in its }{\i desc}{ field.\r
891 \par Finally, the module provides the following utility functions, whose meaning should be obvious:\r
892 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
893 \par void oid_oidcpy(int *t, int *s);\r
894 \par void oid_oidcat(int *t, int *s);\r
895 \par int oid_oidcmp(int *o1, int *o2);\r
896 \par int oid_oidlen(int *o);\r
897 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: The }{\b\i OID}{\i \r
898  module has been criticized - and perhaps rightly so - for needlessly abstracting the representation of OIDs. Other toolkits use a simple string-representation of OIDs with good result\r
899 s. In practice, we have found the interface comfortable and quick to work with, and it is a simple matter (for what it's worth) to create applications compatible with both ISO SR and Z39.50. Finally, the use of the }{\cs27\i\f2\fs20 oident}{\i \r
900  database is by no means mandatory. You can easily create your own system for representing OIDs, as long as it is compatible with the low-level integer-array representation of the ODR module.}{\r
901 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss4_3}{\*\bkmkstart _Toc399132426}4.3 Nibble Memory{\*\bkmkend ss4_3}{\*\bkmkend _Toc399132426}\r
902 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Sometimes when you need to allocate and const\r
903 ruct a large, interconnected complex of structures, it can be a bit of a pain to release the associated memory again. For the structures describing the Z39.50 PDUs and related structures, it is convenient to use the memory-management system of the }{\b \r
904 ODR}{ subsystem (see }{\field{\*\fldinst {HYPERLINK "yaz-5.html" \\l "odr-use"}{\fs20 {\*\datafield \r
905 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d352e68746d6c00ffffadde000000000000000000000000000000000000000000000000080000006f00640072002d0075007300650000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}\r
906 {). However, in some circumstances where you might otherwise benefit from using a simple nibble memory management system, it may be impractical to use }{\cs27\f2\fs20 odr_malloc()}{ and }{\b odr_reset()}{. For this purpose, \r
907 the memory manager which also supports the }{\b ODR}{ streams is made available in the }{\b NMEM}{ module. The external interface to this module is given in the }{\cs27\f2\fs20 nmem.h}{ file.\r
908 \par The following prototypes are given:\r
909 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
910 \par NMEM nmem_create(void);\r
911 \par void nmem_destroy(NMEM n);\r
912 \par void *nmem_malloc(NMEM n, int size);\r
913 \par void nmem_reset(NMEM n);\r
914 \par int nmem_total(NMEM n);\r
915 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 nmem_create()}{ function returns a pointer to a memory control handle, which can be released again by }{\cs27\f2\fs20 \r
916 nmem_destroy()}{ when no longer needed. The function }{\cs27\f2\fs20 nmem_malloc()}{ allocates a block of memory of the requested size. A call to }{\cs27\f2\fs20 nmem_reset()}{ or }{\cs27\f2\fs20 nmem_destroy()}{\r
917  will release all memory allocated on the handle since it was created (or since the last call to }{\cs27\f2\fs20 nmem_reset()}{. The function }{\cs27\f2\fs20 nmem_total()}{ returns the number of bytes currently allocated on the handle.\r
918 \par \r
919 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr}{\*\bkmkstart s5}{\*\bkmkstart _Toc399132427}{\*\bkmkend odr}5. The ODR Module{\*\bkmkend s5}\r
920 {\*\bkmkend _Toc399132427}\r
921 \par {\*\bkmkstart ss5_1}{\*\bkmkstart _Toc399132428}5.1 Introduction{\*\bkmkend ss5_1}{\*\bkmkend _Toc399132428}\r
922 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b ODR}{ is the BER-encoding/decoding subsystem of }{\b YAZ}{. Care as been taken to isolate }{\b ODR}{ from the rest of the package - specif\r
923 ically from the transport interface. }{\b ODR}{ may be used in any context where basic ASN.1/BER representations are used.\r
924 \par If you are only interested in writing a Z39.50 implementation based on the PDUs that are already provided with }{\b YAZ}{, you only need to concern yourself with the section on managing ODR streams (section }{\field{\*\fldinst {HYPERLINK  \\l "odr-use"}{\r
925 \fs20 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b0200000008000000080000006f00640072002d007500730065000000000000}}}{\fldrslt {\cs29\ul\cf2 Using ODR}}}{\r
926 ). Only if you need to implement ASN.1 beyond that which has been provided, should you worry about the second half of the documentation (section }{\field{\*\fldinst {HYPERLINK  \\l "odr-prog"}{\fs20 {\*\datafield \r
927 08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000006f00640072002d00700072006f006700000000}}}{\fldrslt {\cs29\ul\cf2 Programming with ODR}}}{). If you use one of the higher-level interfaces, you can skip this section entirely.\r
928 \par This is important, so we'll repeat it for emphasis: }{\i You do not need to read section }{\field{\*\fldinst {\i HYPERLINK  \\l "odr-prog"}{\i\fs20 {\*\datafield \r
929 08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000006f00640072002d00700072006f006700000000}}}{\fldrslt {\cs29\i\ul\cf2 Programming with ODR}}}{\i  to implement Z39.50 with }{\b\i YAZ}{\i .}{\r
930 \par If you need a part of the protocol that isn't already in }{\b YAZ}{, you should contact the authors before going to work on it yourself: We might already be working on it. Conversely, if you implement a useful part of the protocol before us\r
931 , we'd be happy to include it in a future release.\r
932 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr_use}{\*\bkmkstart ss5_2}{\*\bkmkstart _Toc399132429}{\*\bkmkend odr_use}5.2 Using ODR\r
933 {\*\bkmkend ss5_2}{\*\bkmkend _Toc399132429}\r
934 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {ODR Streams\r
935 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Conceptu\r
936 ally, the ODR stream is the source of encoded data in the decoding mode; when encoding, it is the receptacle for the encoded data. Before you can use an ODR stream it must be allocated. This is done with the function\r
937 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
938 \par ODR odr_createmem(int direction);\r
939 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 odr_createmem()}{ function takes as argument one of three manifest constants: }{\cs27\f2\fs20 ODR_ENCODE}{, }{\r
940 \cs27\f2\fs20 ODR_DECODE}{, or }{\cs27\f2\fs20 ODR_PRINT}{. An ODR stream can be in only one mode - it is not possible to change its mode once it's selected. Typically, your program will allocate at lea\r
941 st two ODR streams - one for decoding, and one for encoding.\r
942 \par When you're done with the stream, you can use\r
943 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
944 \par void odr_destroy(ODR o);\r
945 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to release the resources allocated for the stream.\r
946 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {{\*\bkmkstart memory}{\*\bkmkend memory}Memory Management\r
947 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Two forms of memory managem\r
948 ent take place in the ODR system. The first one, which has to do with allocating little bits of memory (sometimes quite large bits of memory, actually) when a protocol package is decoded, and turned into a complex of interlinked structures. This section d\r
949 eals with this system, and how you can use it for your own purposes. The next section deals with the memory management which is required when encoding data - to make sure that a large enough buffer is available to hold the fully encoded PDU.\r
950 \par The }{\b ODR}{ module \r
951 has its own memory management system, which is used whenever memory is required. Specifically, it is used to allocate space for data when decoding incoming PDUs. You can use the memory system for your own purposes, by using the function\r
952 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
953 \par void *odr_malloc(ODR o, int size);\r
954 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You can't use the normal }{\cs27\f2\fs20 free}{(2) routine to free memory allocated by this function, and }{\b ODR}{\r
955  doesn't provide a parallel function. Instead, you can call\r
956 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
957 \par void odr_reset(ODR o, int size);\r
958 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {when you are done with the memory: Everything allocated since the last call to }{\cs27\f2\fs20 odr_reset()}{ is released. The }{\cs27\f2\fs20 \r
959 odr_reset()}{ call is also required to clear up an error condition on a stream.\r
960 \par The function\r
961 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
962 \par int odr_total(ODR o);\r
963 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {returns the number of bytes allocated on the stream since the last call to }{\cs27\f2\fs20 odr_reset()}{.\r
964 \par The memory subsystem of }{\b ODR}{\r
965  is fairly efficient at allocating and releasing little bits of memory. Rather than managing the individual, small bits of space, the system maintains a freelist of larger chunks of memory, which are handed out in small bits. Thi\r
966 s scheme is generally known as a }{\i nibble memory}{ system. It is very useful for maintaing short-lived constructions such as protocol PDUs.\r
967 \par If you want to retain a bit of memory beyond the next call to }{\cs27\f2\fs20 odr_reset()}{, you can use the function\r
968 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
969 \par ODR_MEM odr_extract_mem(ODR o);\r
970 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This function will give you control of the memory recently allocated on the ODR stream. The memory will live (past calls to }{\cs27\f2\fs20 \r
971 odr_reset()}{), until you call the function\r
972 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
973 \par void odr_release_mem(ODR_MEM p);\r
974 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The opaque }{\cs27\f2\fs20 ODR_MEM}{ handle has no other purpose than referencing the memory block for you until you want to release it.\r
975 \par You can use }{\cs27\f2\fs20 odr_extract_mem()}{ repeatedly between allocating data, to retain individual control of separate chunks of data.\r
976 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Encoding and Decoding Data\r
977 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When encoding data, the ODR stream will write the encoded octet string in an internal buffer. To retrieve the data, use the function\r
978 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
979 \par char *odr_getbuf(ODR o, int *len, int *size);\r
980 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The integer pointed to by len is set to the length of the encoded data, and a pointer to that data is returned. *}{\cs27\f2\fs20 size}{\r
981  is set to the size of the buffer (unless }{\cs27\f2\fs20 size}{ is null, signalling that you are not interested in the size). The next call to a primitive function using the same ODR stream will overwrite the data, unless a different buf\r
982 fer has been supplied using the call\r
983 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
984 \par void odr_setbuf(ODR o, char *buf, int len, int can_grow);\r
985 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which sets the encoding (or decoding) buffer used by }{\cs27\f2\fs20 o}{ to }{\cs27\f2\fs20 buf}{, using the length }{\cs27\f2\fs20 len}{\r
986 . Before a call to an encoding function, you can use }{\cs27\f2\fs20 odr_setbuf()}{ to provide the stream with an encoding buffer of sufficient size (length). The }{\cs27\f2\fs20 can_grow}{\r
987  parameter tells the encoding ODR stream whether it is allowed to use }{\cs27\f2\fs20 realloc}{(2) to increase the size of the buffer when necessary. The default condition of a new encoding stream is equivalent to the results of calling\r
988 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
989 \par odr_setbuf(stream, 0, 0, 1);\r
990 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
991 In this case, the stream will allocate and reallocate memory as necessary. The stream reallocates memory by repeatedly doubling the size of the buffer - the result is that the buffer will\r
992  typically reach its maximum, working size with only a small number of reallocation operations. The memory is freed by the stream when the latter is destroyed, unless it was assigned by the user with the }{\cs27\f2\fs20 can_grow}{\r
993  parameter set to zero (in this case, you are expected to retain control of the memory yourself).\r
994 \par To assume full control of an encoded buffer, you must first call }{\cs27\f2\fs20 odr_getbuf()}{ to fetch the buffer and its length. Next, you should call }{\cs27\f2\fs20 odr_setbuf()}{ to provide a different buffer (or a null pointer) to \r
995 the stream. In the simplest case, you will reuse the same buffer over and over again, and you will just need to call }{\cs27\f2\fs20 odr_getbuf()}{\r
996  after each encoding operation to get the length and address of the buffer. Note that the stream may reallocate the buffer during an encoding operation, so it is necessary to retrieve the correct address after each encoding operation.\r
997 \par It is important to realise that the ODR stream will not release this memory when you call }{\cs27\f2\fs20 odr_reset()}{: It will merely update its internal pointers to prepare for the encoding of a new data value. When the stream is released by the }{\r
998 \cs27\f2\fs20 odr_destroy()}{ function, the memory given to it by odr_setbuf will be released }{\i only}{ if the }{\cs27\f2\fs20 can_grow}{ parameter to }{\cs27\f2\fs20 odr_setbuf()}{ was nonzero. The }{\cs27\f2\fs20 can_grow}{ parameter, in other wo\r
999 rds, is a way of signalling who is to own the buffer, you or the ODR stream. If you never call }{\cs27\f2\fs20 odr_setbuf()}{ on your encoding stream, which is typically the case, the buffer allocated by the stream will belong to the stream by default.\r
1000 \r
1001 \par When you wish to decode data, you should first call }{\cs27\f2\fs20 odr_setbuf()}{, to tell the decoding stream where to find the encoded data, and how long the buffer is (the }{\cs27\f2\fs20 can_grow}{\r
1002  parameter is ignored by a decoding stream). After this, you can call the function corresponding to the data you wish to decode (eg, }{\cs27\f2\fs20 odr_integer()}{ odr }{\cs27\f2\fs20 z_APDU()}{).\r
1003 \par Examples of encoding/decoding functions:\r
1004 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1005 \par int odr_integer(ODR o, int **p, int optional);\r
1006 \par \r
1007 \par int z_APDU(ODR o, Z_APDU **p, int optional);\r
1008 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {If the data is absent (or doesn't match the tag corresponding to the type), the return value will be either 0 or 1 depending on the }{\r
1009 \cs27\f2\fs20 optional}{ flag. If }{\cs27\f2\fs20 optional}{ is 0 and the data is absent, an error flag will be raised in the stream, and you'll need to call }{\cs27\f2\fs20 odr_reset()}{ before you can use the stream again. If }{\cs27\f2\fs20 optional}{\r
1010  is nonzero, the pointer }{\i pointed to}{ by }{\cs27\f2\fs20 p}{ will be set to the null value, and the function will return 1.\r
1011 \par If the data value is found where it's expected, the pointer }{\i pointed to}{ by the }{\cs27\f2\fs20 p}{ argume\r
1012 nt will be set to point to the decoded type. The space for the type will be allocated and owned by the ODR stream, and it will live until you call }{\cs27\f2\fs20 odr_reset()}{ on the stream. You cannot use }{\cs27\f2\fs20 free}{\r
1013 (2) to release the memory. You can decode several data elements (by repeated calls to }{\cs27\f2\fs20 odr_setbuf()}{ and your decoding function), and new memory will be allocated each time. When you do call }{\cs27\f2\fs20 odr_reset()}{\r
1014 , everything decoded since the last call to }{\cs27\f2\fs20 odr_reset()}{ will be released.\r
1015 \par The use of the double indirection can be a li\r
1016 ttle confusing at first (its purpose will become clear later on, hopefully), so an example is in order. We'll encode an integer value, and immediately decode it again using a different stream. A useless, but informative operation.\r
1017 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1018 \par void do_nothing_useful(int value)\r
1019 \par \{\r
1020 \par     ODR encode, decode;\r
1021 \par     int *valp, *resvalp;\r
1022 \par     char *bufferp;\r
1023 \par     int len;\r
1024 \par \r
1025 \par     /* allocate streams */\r
1026 \par     if (!(encode = odr_createmem(ODR_ENCODE)))\r
1027 \par         return;\r
1028 \par     if (!(decode = odr_createmem(ODR_DECODE)))\r
1029 \par         return;\r
1030 \par \r
1031 \par     valp = &value;\r
1032 \par     if (odr_integer(encode, &valp, 0) == 0)\r
1033 \par     \{\r
1034 \par         printf("encoding went bad\\n");\r
1035 \par         return;\r
1036 \par     \}\r
1037 \par     bufferp = odr_getbuf(encode, &len);\r
1038 \par     printf("length of encoded data is %d\\n", len);\r
1039 \par \r
1040 \par     /* now let's decode the thing again */\r
1041 \par     odr_setbuf(decode, bufferp, len);\r
1042 \par     if (odr_integer(decode, &resvalp, 0) == 0)\r
1043 \par     \{\r
1044 \par         printf("decoding went bad\\n");\r
1045 \par         return;\r
1046 \par     \}\r
1047 \par     printf("the value is %d\\n", *resvalp);\r
1048 \par \r
1049 \par     /* clean up */\r
1050 \par     odr_destroy(encode);\r
1051 \par     odr_destroy(decode);\r
1052 \par \}\r
1053 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1054 This looks like a lot of work, offhand. In practice, the ODR streams will typically be allocated once, in the beginning of your program (or at the beginning of a new network session), and the encoding and decoding will only take \r
1055 place in a few, isolated places in your program, so the overhead is quite manageable.\r
1056 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Diagnostics\r
1057 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The encoding/decoding functions all return 0 when an error occurs. Until you call }{\cs27\f2\fs20 odr_reset()}{\r
1058 , you cannot use the stream again, and any function called will immediately return 0.\r
1059 \par To provide information to the programmer or administrator, the function\r
1060 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1061 \par void odr_perror(ODR o, char *message);\r
1062 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {is provided, which prints the }{\cs27\f2\fs20 message}{ argument to }{\cs27\f2\fs20 stderr}{ along with an error message from the stream.\r
1063 \r
1064 \par You can also use the function\r
1065 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1066 \par int odr_geterror(ODR o);\r
1067 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to get the current error number from the screen. The number will be one of these constants:\r
1068 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OMEMORY}{\r
1069 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Memory allocation failed.\r
1070 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OSYSERR}{\r
1071 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A system- or library call has failed. The standard diagnostic variable }{\cs27\f2\fs20 errno}{ should be \r
1072 examined to determine the actual error.\r
1073 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OSPACE}{\r
1074 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1075 No more space for encoding. This will only occur when the user has explicitly provided a buffer for an encoding stream without allowing the system to allocate more space.\r
1076 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OREQUIRED}{\r
1077 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This is a common protocol error; A required data element was missing during encoding or decoding.\r
1078 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OUNEXPECTED}{\r
1079 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {An unexpected data element was found during decoding.\r
1080 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b OOTHER}{\r
1081 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Other error. This is typically an indication of misuse of the }{\b ODR}{\r
1082  system by the programmer, and also that the diagnostic system isn't as good as it should be, yet.\r
1083 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The character string array\r
1084 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1085 \par char *odr_errlist[]\r
1086 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {can be indexed by the error code to obtain a human-readable representation of the problem.\r
1087 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Summary and Synopsis\r
1088 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1089 \par #include <odr.h>\r
1090 \par \r
1091 \par ODR odr_createmem(int direction);\r
1092 \par \r
1093 \par void odr_destroy(ODR o);\r
1094 \par \r
1095 \par void odr_reset(ODR o);\r
1096 \par \r
1097 \par char *odr_getbuf(ODR o, int *len);\r
1098 \par \r
1099 \par void odr_setbuf(ODR o, char *buf, int len);\r
1100 \par \r
1101 \par void *odr_malloc(ODR o, int size);\r
1102 \par \r
1103 \par ODR_MEM odr_extract_mem(ODR o);\r
1104 \par \r
1105 \par void odr_release_mem(ODR_MEM r);\r
1106 \par \r
1107 \par int odr_geterror(ODR o);\r
1108 \par \r
1109 \par void odr_perror(char *message);\r
1110 \par \r
1111 \par extern char *odr_errlist[];\r
1112 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart odr_prog}{\*\bkmkstart ss5_3}{\*\bkmkstart _Toc399132430}{\*\bkmkend odr_prog}5.3 Programming with ODR\r
1113 {\*\bkmkend ss5_3}{\*\bkmkend _Toc399132430}\r
1114 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The API of }{\b ODR}{ is desig\r
1115 ned to reflect the structure of ASN.1, rather than BER itself. Future releases may be able to represent data in other external forms.\r
1116 \par The interface is based loosely on that of the Sun Microsystems XDR routines. Specifically, each function which corresponds\r
1117  to an ASN.1 primitive type has a dual function. Depending on the settings of the ODR stream which is supplied as a parameter, the function may be used either to encode or decode data. The functions that can be built using these primitive functions, to re\r
1118 p\r
1119 resent more complex datatypes, share this quality. The result is that you only have to enter the definition for a type once - and you have the functionality of encoding, decoding (and pretty-printing) all in one unit. The resulting C source code is quite \r
1120 compact, and is a pretty straightforward representation of the source ASN.1 specification. Although no ASN.1 compiler is supplied with }{\b ODR}{\r
1121  at this time, it shouldn't be too difficult to write one, or perhaps even to adapt an existing compiler to output }{\b ODR}{ routines (not surprisingly, writing encoders/decoders using }{\b ODR}{ turns out to be boring work).\r
1122 \par In many cases, the model of the XDR functions works quite well in this role. In others, it is less elegant. Most of the hassle comes from the optional SEQUENCE memebers which don't exist in XDR.\r
1123 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {The Primitive ASN.1 Types\r
1124 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {ASN.1 defines a number of primitive types (many of which correspond roughly to primitive types in structured programming languages, such as C).\r
1125 \r
1126 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {INTEGER\r
1127 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b ODR}{ function for encoding or decoding (or printing) the ASN.1 INTEGER type looks like this:\r
1128 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1129 \par int odr_integer(ODR o, int **p, int optional);\r
1130 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {(we don't allow values that can't be contained in a C integer.)\r
1131 \par This form is typical of the primitive }{\b ODR}{ functions. They are named after the type of data that they encode or decode. They take an ODR stream, an indirect reference to the type in question, and an }{\cs27\f2\fs20 optional}{\r
1132  flag (corresponding to the OPTIONAL keyword of ASN.1) as parameters. They all return an integer value of either one or zero. When you use the \r
1133 primitive functions to construct encoders for complex types of your own, you should follow this model as well. This ensures that your new types can be reused as elements in yet more complex types.\r
1134 \par The }{\cs27\f2\fs20 o}{ parameter should obviously refer to a properly initialized ODR stream of the right type (encoding/decoding/printing) for the operation that you wish to perform.\r
1135 \par When encoding or printing, the function first looks at *}{\cs27\f2\fs20 p}{. If *}{\cs27\f2\fs20 p}{ (the pointer pointed to by }{\cs27\f2\fs20 p}{) is a null pointer, this is taken to mean that the data element is absent. If the }{\cs27\f2\fs20 optional}\r
1136 { parameter is nonzero, the function will return one (signifying success) without any further processing. If the }{\cs27\f2\fs20 optional}{ is zero, an internal error flag is set in the ODR stream, and the function will return 0. No furthe\r
1137 r operations can be carried out on the stream without a call to the function }{\cs27\f2\fs20 odr_reset()}{.\r
1138 \par If *}{\cs27\f2\fs20 p}{ is not a null pointer, it is expected to point to an instance of the data type. The data will be subjected to the encoding rules, and the result will be placed in the buffer held by the ODR stream.\r
1139 \par The other ASN.1 primitives have similar functions that operate in similar manners:\r
1140 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {BOOLEAN\r
1141 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1142 \par int odr_bool(ODR o, bool_t **p, int optional);\r
1143 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {REAL\r
1144 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Not defined.\r
1145 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {NULL\r
1146 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1147 \par int odr_null(ODR o, bool_t **p, int optional);\r
1148 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In this case, the value of **p is not important. If *p is different from the null pointer, the null value is present, otherwise it's absent.\r
1149 \r
1150 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OCTET STRING\r
1151 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1152 \par typedef struct odr_oct\r
1153 \par \{\r
1154 \par     unsigned char *buf;\r
1155 \par     int len;\r
1156 \par     int size;\r
1157 \par \} Odr_oct;\r
1158 \par \r
1159 \par int odr_octetstring(ODR o, Odr_oct **p, int optional);\r
1160 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 buf}{ field should point to the character array that holds the octetstring. The }{\cs27\f2\fs20 len}{\r
1161  field holds the actual length, while the }{\cs27\f2\fs20 size}{ field gives the size of the allocated array (not of interest to you, in most cases). The character array need not be null terminated.\r
1162 \par To make things a little easier, an alternative is given for string types that are not expected to contain embedded NULL characters (eg. VisibleString):\r
1163 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1164 \par int odr_cstring(ODR o, char **p, int optional);\r
1165 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Which encoded or decodes between OCTETSTRING representations and null-terminates C strings.\r
1166 \par Functions are provided for the derived string types, eg:\r
1167 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1168 \par int odr_visiblestring(ODR o, char **p, int optional);\r
1169 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {BIT STRING\r
1170 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1171 \par int odr_bitstring(ODR o, Odr_bitmask **p, int optional);\r
1172 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The opaque type }{\cs27\f2\fs20 Odr_bitmask}{\r
1173  is only suitable for holding relatively brief bit strings, eg. for options fields, etc. The constant }{\cs27\f2\fs20 ODR_BITMASK_SIZE}{ multiplied by 8 gives the maximum possible number of bits.\r
1174 \par A set of macros are provided for manipulating the }{\cs27\f2\fs20 Odr_bitmask}{ type:\r
1175 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1176 \par void ODR_MASK_ZERO(Odr_bitmask *b);\r
1177 \par \r
1178 \par void ODR_MASK_SET(Odr_bitmask *b, int bitno);\r
1179 \par \r
1180 \par void ODR_MASK_CLEAR(Odr_bitmask *b, int bitno);\r
1181 \par \r
1182 \par int ODR_MASK_GET(Odr_bitmask *b, int bitno);\r
1183 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The functions are modelled after the manipulation functions that accompany the }{\cs27\f2\fs20 fd_set}{ type used by the }{\cs27\f2\fs20 select\r
1184 }{(2) call. }{\cs27\f2\fs20 ODR_MASK_ZERO}{ should always be called first on a new bitmask, to initialize the bits to zero.\r
1185 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OBJECT IDENTIFIER\r
1186 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1187 \par int odr_oid(ODR o, Odr_oid **p, int optional);\r
1188 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The C OID represenation is simply an array of integers, terminated by the value -1 (the }{\cs27\f2\fs20 Odr_oid}{ type is synonymous with the }\r
1189 {\cs27\f2\fs20 int}{ type). We suggest that you use the OID database module (see section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 {\*\datafield \r
1190 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 Object Identifiers}}}{\r
1191 ) to handle object identifiers in your application.\r
1192 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {{\*\bkmkstart tag_prim}{\*\bkmkend tag_prim}Tagging Primitive Types\r
1193 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The simplest way of tagging a type is to use the }{\cs27\f2\fs20 odr_implicit()}{ or }{\cs27\f2\fs20 odr_explicit()}{ macros:\r
1194 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1195 \par int odr_implicit(ODR o, Odr_fun fun, int class, int tag, int\r
1196 \par                     optional);\r
1197 \par \r
1198 \par int odr_explicit(ODR o, Odr_fun fun, int class, int tag,\r
1199 \par                     int optional);\r
1200 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To create a type derived from the integer type by implicit tagging, you might write:\r
1201 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1202 \par MyInt ::= [210] IMPLICIT INTEGER\r
1203 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In the }{\b ODR}{ system, this would be written like:\r
1204 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1205 \par int myInt(ODR o, int **p, int optional)\r
1206 \par \{\r
1207 \par     return odr_implicit(o, odr_integer, p, ODR_CONTEXT, 210, optional);\r
1208 \par \}\r
1209 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The function }{\cs27\f2\fs20 myInt()}{ can then be used like any of the primitive functions provided by ODR. Note that the behavior of }{\r
1210 \cs27\f2\fs20 odr_explicit()}{ and }{\cs27\f2\fs20 odr_implicit()}{\r
1211  macros act exactly the same as the functions they are applied to - they respond to error conditions, etc, in the same manner - they simply have three extra parameters. The class parameter may take one of the values: }{\cs27\f2\fs20 ODR_CONTEXT}{, }{\r
1212 \cs27\f2\fs20 ODR_PRIVATE}{, }{\cs27\f2\fs20 ODR_UNIVERSAL}{, or }{\cs27\f2\fs20 ODR_APPLICATION}{.\r
1213 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Constructed Types\r
1214 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Constructed types are created by combining primitive types. The }{\b ODR}{\r
1215  system only implements the SEQUENCE and SEQUENCE OF constructions (although adding the rest of the container types should be simple enough, if the need arises).\r
1216 \par For implementing SEQUENCEs, the functions\r
1217 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1218 \par int odr_sequence_begin(ODR o, void *p, int size);\r
1219 \par int odr_sequence_end(ODR o);\r
1220 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {are provided.\r
1221 \par The }{\cs27\f2\fs20 odr_sequence_begin()}{ function should be called in the beginning of a function that implements a SEQUENCE type. Its parameters are the }{\b ODR}{ stream, a pointer (to a pointer to the type you're implementing), and the }{\r
1222 \cs27\f2\fs20 size}{ of the type (typically a C structure). On encoding, it returns 1 if *}{\cs27\f2\fs20 p}{ is a null pointer. The }{\cs27\f2\fs20 size}{ parameter is ignored. On decoding, it returns 1 if the type is found in the data stream. }{\r
1223 \cs27\f2\fs20 size}{ bytes of memory are allocated, and *}{\cs27\f2\fs20 p}{ is set to point to this space. }{\cs27\f2\fs20 odr_sequence_end()}{ is called at the end of the complex function. Assume that a type is defined like this:\r
1224 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1225 \par MySequence ::= SEQUENCE \{\r
1226 \par     intval INTEGER,\r
1227 \par     boolval BOOLEAN OPTIONAL \}\r
1228 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The corresponding ODR encoder/decoder function and the associated data structures could be written like this:\r
1229 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1230 \par typedef struct MySequence\r
1231 \par \{\r
1232 \par     int *intval;\r
1233 \par     bool_t *boolval;\r
1234 \par \} MySequence;\r
1235 \par \r
1236 \par int mySequence(ODR o, MySequence **p, int optional)\r
1237 \par \{\r
1238 \par     if (odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
1239 \par         return optional && odr_ok(o);\r
1240 \par     return\r
1241 \par         odr_integer(o, &(*p)->intval, 0) &&\r
1242 \par         odr_bool(o, &(*p)->boolval, 1) &&\r
1243 \par         odr_sequence_end(o);\r
1244 \par \}\r
1245 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Note the 1 in the call to }{\cs27\f2\fs20 odr_bool()}{\r
1246 , to mark that the sequence member is optional. If either of the member types had been tagged, the macros }{\cs27\f2\fs20 odr_implicit()}{ or }{\cs27\f2\fs20 odr_explicit()}{\r
1247  could have been used. The new function can be used exactly like the standard functions provided with }{\b ODR}{. It will encode, decode or pretty-print a data value of the }{\cs27\f2\fs20 MySequence}{\r
1248  type. We like to name types with an initial capital, as done in ASN.1 definitio\r
1249 ns, and to name the corresponding function with the first character of the name in lower case. You could, of course, name your structures, types, and functions any way you please - as long as you're consistent, and your code is easily readable. }{\r
1250 \cs27\f2\fs20 odr_ok}{ is just that - a predicate that returns the state of the stream. It is used to ensure that the behaviour of the new type is compatible with the interface of the primitive types.\r
1251 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Tagging Constructed Types\r
1252 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: See section }{\field{\*\fldinst {\i HYPERLINK  \\l "tag-prim"}{\i\fs20 {\*\datafield \r
1253 08d0c9ea79f9bace118c8200aa004ba90b0200000008000000090000007400610067002d007000720069006d00000000}}}{\fldrslt {\cs29\i\ul\cf2 Tagging Primitive types}}}{\i  for information on how to tag the primitive types, as well as types that are already defined.}{\r
1254 \r
1255 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Implicit Tagging\r
1256 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assume the type above had been defined as\r
1257 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1258 \par MySequence ::= [10] IMPLICIT SEQUENCE \{\r
1259 \par     intval INTEGER,\r
1260 \par     boolval BOOLEAN OPTIONAL \}\r
1261 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {You would implement this in }{\b ODR}{ by calling the function\r
1262 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1263 \par int odr_implicit_settag(ODR o, int class, int tag);\r
1264 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {which overrides the tag of the type immediately following it. The macro }{\cs27\f2\fs20 odr_implicit()}{ works by calling }{\cs27\f2\fs20 \r
1265 odr_implicit_settag()}{ immediately before calling the function pointer argument. Your type function could look like this:\r
1266 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1267 \par int mySequence(ODR o, MySequence **p, int optional)\r
1268 \par \{\r
1269 \par     if (odr_implicit_settag(o, ODR_CONTEXT, 10) == 0 ||\r
1270 \par         odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
1271 \par         return optional && odr_ok(o);\r
1272 \par     return\r
1273 \par         odr_integer(o, &(*p)->intval, 0) &&\r
1274 \par         odr_bool(o, &(*p)->boolval, 1) &&\r
1275 \par         odr_sequence_end(o);\r
1276 \par \}\r
1277 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The definition of the structure }{\cs27\f2\fs20 MySequence}{ would be the same.\r
1278 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Explicit Tagging\r
1279 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Explicit tagging of constructed types is a little more complicated, since you are in effect adding a level of construction to the data.\r
1280 \par Assume the definition:\r
1281 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1282 \par MySequence ::= [10] IMPLICIT SEQUENCE \{\r
1283 \par     intval INTEGER,\r
1284 \par     boolval BOOLEAN OPTIONAL \}\r
1285 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Since the new type has an extra level of construction, two new functions are needed to encapsulate the base type:\r
1286 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1287 \par int odr_constructed_begin(ODR o, void *p, int class, int tag);\r
1288 \par \r
1289 \par int odr_constructed_end(ODR o);\r
1290 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Assume that the IMPLICIT in the type definiti\r
1291 on above were replaced with EXPLICIT (or that the IMPLICIT keyword were simply deleted, which would be equivalent). The structure definition would look the same, but the function would look like this:\r
1292 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1293 \par int mySequence(ODR o, MySequence **p, int optional)\r
1294 \par \{\r
1295 \par     if (odr_constructed_begin(o, p, ODR_CONTEXT, 10) == 0)\r
1296 \par         return optional && odr_ok(o);\r
1297 \par     if (o->direction == ODR_DECODE)\r
1298 \par         *p = odr_malloc(o, sizeof(**p));\r
1299 \par     if (odr_sequence_begin(o, p, sizeof(**p)) == 0)\r
1300 \par     \{\r
1301 \par         *p = 0; /* this is almost certainly a protocol error */\r
1302 \par         return 0;\r
1303 \par     \}\r
1304 \par     return\r
1305 \par         odr_integer(o, &(*p)->intval, 0) &&\r
1306 \par         odr_bool(o, &(*p)->boolval, 1) &&\r
1307 \par         odr_sequence_end(o) &&\r
1308 \par         odr_constructed_end(o);\r
1309 \par \}\r
1310 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1311 Notice that the interface here gets kind of nasty. The reason is simple: Explicitly tagged, constructed types are fairly rare in the protocols that we care about, so the aesthetic annoyance (not to mention the dangers of a cluttered interface) is less tha\r
1312 n the time that would be required to develop a better interface. Nevertheless, it is far from satisfying, and it's a point that will be worked on in the future. One option for you would be to simply apply the }{\cs27\f2\fs20 odr_explicit()}{\r
1313  macro to the first function, and not have to worry about }{\cs27\f2\fs20 odr_constructed_*}{ yourself. Incidentally, as you might have guessed, the }{\cs27\f2\fs20 odr_sequence_}{ functions are themselves implemented using the }{\cs27\f2\fs20 \r
1314 odr_constructed_}{ functions.\r
1315 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {SEQUENCE OF\r
1316 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To handle sequences (arrays) of a apecific type, the function\r
1317 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1318 \par int odr_sequence_of(ODR o, int (*fun)(ODR o, void *p, int optional),\r
1319 \par                         void *p, int *num);\r
1320 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 fun}{ parameter is a pointer to the decoder/encoder function of the type. }{\cs27\f2\fs20 p}{\r
1321  is a pointer to an array of pointers to your type. }{\cs27\f2\fs20 num}{ is the number of elements in the array.\r
1322 \par Assume a type\r
1323 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1324 \par MyArray ::= SEQUENCE OF INTEGER\r
1325 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The C representation might be\r
1326 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1327 \par typedef struct MyArray\r
1328 \par \{\r
1329 \par     int num_elements;\r
1330 \par     int **elements;\r
1331 \par \} MyArray;\r
1332 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {And the function might look like\r
1333 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1334 \par int myArray(ODR o, MyArray **p, int optional)\r
1335 \par \{\r
1336 \par     if (o->direction == ODR_DECODE)\r
1337 \par         *p = odr_malloc(o, sizeof(**p));\r
1338 \par     if (odr_sequence_of(o, odr_integer, &(*p)->elements,\r
1339 \par         &(*p)->num_elements))\r
1340 \par         return 1;\r
1341 \par     *p = 0;\r
1342 \par     return optional && odr_ok(o);\r
1343 \par \}\r
1344 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {CHOICE Types\r
1345 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The choice type is used fairly often in some ASN.1 definitions, so some work has gone into streamlining its interface.\r
1346 \par CHOICE types are handled by the function:\r
1347 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1348 \par int odr_choice(ODR o, Odr_arm arm[], void *p, int *whichp);\r
1349 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 arm}{ array is used\r
1350  to describe each of the possible types that the CHOICE type may assume. Internally in your application, the CHOICE type is represented as a discriminated union. That is, a C union accompanied by an integer (or enum) identifying the active 'arm' of the un\r
1351 ion. }{\cs27\f2\fs20 whichp}{ is a pointer to the union discriminator. When encoding, it is examined to determine the current type. When decoding, it is set to reference the type that was found in the input stream.\r
1352 \par The Odr_arm type is defined thus:\r
1353 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1354 \par typedef struct odr_arm\r
1355 \par \{\r
1356 \par     int tagmode;\r
1357 \par     int class;\r
1358 \par     int tag;\r
1359 \par     int which;\r
1360 \par     Odr_fun fun;\r
1361 \par \} Odr_arm;\r
1362 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The interpretation of the fields are:\r
1363 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b tagmode}{\r
1364 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Either }{\cs27\f2\fs20 ODR_IMPLICIT}{, }{\cs27\f2\fs20 ODR_EXPLICIT}{, or }{\cs27\f2\fs20 ODR_NONE}{ (-1) to mark no tagging.\r
1365 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b class, tag}{\r
1366 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The class and tag of the type (-1 if no tagging is used).\r
1367 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b which}{\r
1368 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The value of the discriminator that corresponds to this CHOICE element. Typically, it will be a #defined constant, or an enum member.\r
1369 \r
1370 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b fun}{\r
1371 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A pointer to a function that implements the type of the CHOICE member. It may be either a standard }{\b ODR}{\r
1372  type or a type defined by yourself.\r
1373 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A handy way to prepare the array for use by the }{\cs27\f2\fs20 odr_choice()}{\r
1374  function is to define it as a static, initialized array in the beginning of your decoding/encoding function. Assume the type definition:\r
1375 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1376 \par MyChoice ::= CHOICE \{\r
1377 \par     untagged INTEGER,\r
1378 \par     tagged   [99] IMPLICIT INTEGER,\r
1379 \par     other    BOOLEAN\r
1380 \par \}\r
1381 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Your C type might look like\r
1382 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1383 \par typedef struct MyChoice\r
1384 \par \{\r
1385 \par     enum\r
1386 \par     \{\r
1387 \par         MyChoice_untagged,\r
1388 \par         MyChoice_tagged,\r
1389 \par         MyChoice_other\r
1390 \par     \} which;\r
1391 \par     union\r
1392 \par     \{\r
1393 \par         int *untagged;\r
1394 \par         int *tagged;\r
1395 \par         bool_t *other;\r
1396 \par     \} u;\r
1397 \par \};\r
1398 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {And your function could look like this:\r
1399 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1400 \par int myChoice(ODR o, MyChoice **p, int optional)\r
1401 \par \{\r
1402 \par     static Odr_arm arm[] =\r
1403 \par     \{\r
1404 \par         \{-1, -1, -1, MyChoice_untagged, odr_integer\},\r
1405 \par         \{ODR_IMPLICIT, ODR_CONTEXT, 99, MyChoice_tagged, odr_integer\},\r
1406 \par         \{-1, -1, -1, MyChoice_other, odr_boolean\},\r
1407 \par         \{-1, -1, -1, -1, 0\}\r
1408 \par     \};\r
1409 \par \r
1410 \par     if (o->direction == ODR_DECODE)\r
1411 \par         *p = odr_malloc(o, sizeof(**p);\r
1412 \par     else if (!*p)\r
1413 \par         return optional && odr_ok(o);\r
1414 \par \r
1415 \par     if (odr_choice(o, arm, &(*p)->u, &(*p)->which))\r
1416 \par         return 1;\r
1417 \par     *p = 0;\r
1418 \par     return optional && odr_ok(o);\r
1419 \par \}\r
1420 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {In some cases (say, a non-optional choice which is a membe\r
1421 r of a sequence), you can "embed" the union and its discriminator in the structure belonging to the enclosing type, and you won't need to fiddle with memory allocation to create a separate structure to wrap the discriminator and union.\r
1422 \par The corresponding function is somewhat nicer in the Sun XDR interface. Most of the complexity of this interface comes from the possibility of declaring sequence elements (including CHOICEs) optional.\r
1423 \par The ASN.1 specifictions naturally requires that each member of a CHOICE have\r
1424  a distinct tag, so they can be told apart on decoding. Sometimes it can be useful to define a CHOICE that has multiple types that share the same tag. You'll need some other mechanism, perhaps keyed to the context of the CHOICE type. In effect, we would l\r
1425 i\r
1426 ke to introduce a level of context-sensitiveness to our ASN.1 specification. When encoding an internal representation, we have no problem, as long as each CHOICE member has a distinct discriminator value. For decoding, we need a way to tell the choice fun\r
1427 ction to look for a specific arm of the table. The function\r
1428 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1429 \par void odr_choice_bias(ODR o, int what);\r
1430 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {provides this functionality. When called, it leaves a notice for the next call to }{\cs27\f2\fs20 odr_choice()}{\r
1431  to be called on the decoding stream }{\cs27\f2\fs20 o}{ that only the }{\cs27\f2\fs20 arm}{ entry with a }{\cs27\f2\fs20 which}{ field equal to }{\cs27\f2\fs20 what}{ should be tried.\r
1432 \par The most important application (perhaps the only one, really) is in the definition of application-specific EXTERNAL encoders/decoders which will automatically decode an ANY member given the direct or indirect reference.\r
1433 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss5_4}{\*\bkmkstart _Toc399132431}5.4 Debugging{\*\bkmkend ss5_4}{\*\bkmkend _Toc399132431}\r
1434 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1435 The protocol modules are suffering somewhat from a lack of diagnostic tools at the moment. Specifically ways to pretty-print PDUs that aren't recognized by the system. We'll include something \r
1436 to this end in a not-too-distant release. In the meantime, what we do when we get packages we don't understand is to compile the ODR module with }{\cs27\f2\fs20 ODR_DEBUG}{\r
1437  defined. This causes the module to dump tracing information as it processes data units. With this output and the protocol specification (Z39.50), it is generally fairly easy to see what goes wrong.{\*\bkmkstart comstack}{\*\bkmkstart s6}\r
1438 {\*\bkmkend comstack}\r
1439 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart _Toc399132432}6. The COMSTACK Module{\*\bkmkend s6}{\*\bkmkend _Toc399132432}\r
1440 \par {\*\bkmkstart ss6_1}{\*\bkmkstart _Toc399132433}6.1 Introduction{\*\bkmkend ss6_1}{\*\bkmkend _Toc399132433}\r
1441 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\b COMSTACK}{\r
1442  subsystem provides a transparent interface to different types of transport stacks for the exchange of BER-encoded data. At present, the RFC1729 method (BER over TCP/IP), and Peter Furniss' XTImOSI stack are supported, but others may be added in time. The\r
1443  philosophy of the module is to provide a simple interface by hiding unused options and facilities of the underlying libraries. This is always done at the risk of losing generality, and it may prove that the interface will need extension later on.\r
1444 \par The interface is implemented in such a fashion that only the sub-layers constructed to the transport methods that you wish to use in your application are linked in.\r
1445 \par You will note that even though simplicity was a goal in the design, the interface is still orders of\r
1446  magnitudes more complex than the transport systems found in many other packages. One reason is that the interface needs to support the somewhat different requirements of the different lower-layer communications stacks; another important reason is that th\r
1447 e\r
1448  interface seeks to provide a more or less industrial-strength approach to asynchronous event-handling. When no function is allowed to block, things get more complex - particularly on the server side. We urge you to have a look at the demonstration client\r
1449  and server provided with the package. They are meant to be easily readable and instructive, while still being at least moderately useful.\r
1450 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_2}{\*\bkmkstart _Toc399132434}6.2 Common Functions{\*\bkmkend ss6_2}{\*\bkmkend _Toc399132434}\r
1451 \r
1452 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Managing Endpoints\r
1453 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1454 \par COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);\r
1455 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Creates an instance of the protocol stack - a communications endpoint. The }{\cs27\f2\fs20 type}{\r
1456  parameter determines the mode of communication. At present, the values }{\cs27\f2\fs20 tcpip_type}{ and }{\cs27\f2\fs20 mosi_type}{ are recognized. The function returns a null-pointer if a system error occurs. The }{\cs27\f2\fs20 blocking}{\r
1457  parameter should be one if you wish the association to operate in blocking mode, zero otherwise. The }{\cs27\f2\fs20 protocol}{ field should be one of }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{.\r
1458 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1459 \par int cs_close(COMSTACK handle);\r
1460 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Closes the connection (as elegantly as the lower layers will permit), and releases the resouces pointed to by the }{\cs27\f2\fs20 handle}{\r
1461  parameter. The }{\cs27\f2\fs20 handle}{ should not be referenced again after this call.\r
1462 \par }{\i NOTE: We really need a soft disconnect, don't we?}{\r
1463 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Data Exchange\r
1464 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1465 \par int cs_put(COMSTACK handle, char *buf, int len);\r
1466 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Sends }{\cs27\f2\fs20 buf}{\r
1467  down the wire. In blocking mode, this function will return only when a full buffer has been written, or an error has occurred. In nonblocking mode, it's possible that the function will be unable to\r
1468  send the full buffer at once, which will be indicated by a return value of 1. The function will keep track of the number of octets already written; you should call it repeatedly with the same values of }{\cs27\f2\fs20 buf}{ and }{\cs27\f2\fs20 len}{\r
1469 , until the buffer has been transmitted. When a full buffer has been sent, the function will return 0 for success. -1 indicates an error condition (see below).\r
1470 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1471 \par int cs_get(COMSTACK handle, char **buf, int *size);\r
1472 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Receives a PDU from the peer. Returns the number of bytes read. In nonblocking mode, \r
1473 it is possible that not all of the packet can be read at once. In this case, the function returns 1. To simplify the interface, the function is responsible for managing the size of the buffer. It will be reallocated if necessary to contain large packages,\r
1474  and will sometimes be moved around internally by the subsystem when partial packages are read. Before calling }{\cs27\f2\fs20 cs_get}{\r
1475  for the fist time, the buffer can be initialized to the null pointer, and the length should also be set to 0 - cs_get will perform a }{\cs27\f2\fs20 malloc}{\r
1476 (2) on the buffer for you. When a full buffer has been read, the size of the package is returned (which will always be greater than 1). -1 indicates an error condition.\r
1477 \par See also the }{\cs27\f2\fs20 cs_more()}{ function below.\r
1478 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1479 \par int cs_more(COMSTACK handle);\r
1480 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 cs_more()}{ function should be used in conjunction with }{\cs27\f2\fs20 cs_get}{ and }{\cs27\f2\fs20 select}{(2). The }{\r
1481 \cs27\f2\fs20 cs_get()}{ function will sometimes (notably in the TCP/IP mode) read more than a single protocol package off the network. When this happens, the extra package is stored by the subsystem. After calling }{\cs27\f2\fs20 cs_get()}{\r
1482 , and before waiting for more input, You should always call }{\cs27\f2\fs20 cs_more()}{ to check if there's a full protocol package already read. If }{\cs27\f2\fs20 cs_more()}{ returns 1, }{\cs27\f2\fs20 cs_get()}{\r
1483  can be used to immediately fetch the new package. For the mOSI subsystem, the function should always return 0, but if you want your stuff to be protocol independent, you should use it.\r
1484 \par }{\i NOTE: The }{\cs27\i\f2\fs20 cs_more()}{\i  function is required because the RFC1729-method does not provide a way of separating individual PDUs, short of partially decodin\r
1485 g the BER. Some other implementations will carefully nibble at the packet by calling }{\cs27\i\f2\fs20 read}{\i (2) several times. This was felt to be too inefficient (or at least clumsy) - hence the call for this extra function.}{\r
1486 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1487 \par int cs_look(COMSTACK handle);\r
1488 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {This function is useful when you're operating in nonblocking mode. Call it when }{\cs27\f2\fs20 select}{\r
1489 (2) tells you there's something happening on the line. It returns one of the following values:\r
1490 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_NONE}{\r
1491 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {No event is pending. The data found on the line was not a complete package.\r
1492 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_CONNECT}{\r
1493 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A response to your connect request has been received. Call }{\cs27\f2\fs20 cs_rcvconnect}{\r
1494  to process the event and to finalize the connection establishment.\r
1495 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_DISCON}{\r
1496 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The other side has closed the connection (or maybe sent a disconnect request - but do we care? Maybe later). Call }{\cs27\f2\fs20 \r
1497 cs_close}{ To close your end of the association as well.\r
1498 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_LISTEN}{\r
1499 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {A connect request has been received. Call }{\cs27\f2\fs20 cs_listen}{ to process the event.\r
1500 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\b CS_DATA}{\r
1501 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {There's data to be found on the line. Call }{\cs27\f2\fs20 cs_get}{ to get it.\r
1502 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i NOTE: You should be aware that even if }{\cs27\i\f2\fs20 cs_look()}{\i \r
1503  tells you that there's an event event pending, the corresponding function may still return and tell you there was nothing to be found. This means that only part of a package was available for reading. The same event will show u\r
1504 p again, when more data has arrived.}{\r
1505 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1506 \par int cs_fileno(COMSTACK h);\r
1507 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Returns the file descriptor of the association. Use this when file-level operations on the endpoint are required (}{\cs27\f2\fs20 select}{\r
1508 (2) operations, specifically).\r
1509 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_3}{\*\bkmkstart _Toc399132435}6.3 Client Side{\*\bkmkend ss6_3}{\*\bkmkend _Toc399132435}\r
1510 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1511 \par int cs_connect(COMSTACK handle, void *address);\r
1512 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Initiate a connection with the target at }{\cs27\f2\fs20 address}{\r
1513  (more on addresses below). The function will return 0 on success, and 1 if the operation does not complete immediately (this will only happen on a nonblocking endpoint). In this case, use }{\cs27\f2\fs20 cs_rcvconnect}{ to complete the operation, when }{\r
1514 \cs27\f2\fs20 select}{(2) reports input pending on the association.\r
1515 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1516 \par int cs_rcvconnect(COMSTACK handle);\r
1517 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Complete a connect operation initiated by }{\cs27\f2\fs20 cs_connect()}{. It will return 0 on suc\r
1518 cess; 1 if the operation has not yet completed (in this case, call the function again later); -1 if an error has occured.\r
1519 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_4}{\*\bkmkstart _Toc399132436}6.4 Server Side{\*\bkmkend ss6_4}{\*\bkmkend _Toc399132436}\r
1520 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To establish a server under the }{\cs27\f2\fs20 inetd}{ server, you can use\r
1521 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1522 \par COMSTACK cs_createbysocket(int socket, CS_TYPE type, int blocking,\r
1523 \par                               int protocol);\r
1524 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\i socket}{ parameter is an established socket (when your application is invoked from }{\cs27\f2\fs20 inetd}{\r
1525 , the socket will typically be 0. The following parameters are identical to the ones for }{\cs27\f2\fs20 cs_create}{.\r
1526 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1527 \par int cs_bind(COMSTACK handle, void *address, int mode)\r
1528 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Binds a local address to the endpoint. Read about addresses below. The }{\cs27\f2\fs20 mode}{ parameter should be either }{\cs27\f2\fs20 \r
1529 CS_CLIENT}{ or }{\cs27\f2\fs20 CS_SERVER}{.\r
1530 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1531 \par int cs_listen(COMSTACK handle, char *addr, int *addrlen);\r
1532 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1533 Call this to process incoming events on an endpoint that has been bound in listening mode. It will return 0 to indicate that the connect request has been received, 1 to signal a partial reception, and -1 to indicate an error condition.\r
1534 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1535 \par COMSTACK cs_accept(COMSTACK handle);\r
1536 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1537 This finalises the server-side association establishment, after cs_listen has completed successfully. It returns a new connection endpoint, which represe\r
1538 nts the new association. The application will typically wish to fork off a process to handle the association at this point, and continue listen for new connections on the old }{\cs27\f2\fs20 handle}{.\r
1539 \par You can use the call\r
1540 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1541 \par char *cs_addrstr(COMSTACK);\r
1542 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {on an established connection to retrieve the hostname of the remote host.\r
1543 \par }{\i NOTE: You may need to use this function with some care if your name server service is slow or unreliable}{\r
1544 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_5}{\*\bkmkstart _Toc399132437}6.5 Addresses{\*\bkmkend ss6_5}{\*\bkmkend _Toc399132437}\r
1545 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The low-level format of the addresses are differen\r
1546 t depending on the mode of communication you have chosen. A function is provided by each of the lower layers to map a user-friendly string-form address to the binary form required by the lower layers.\r
1547 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1548 \par struct sockaddr_in *tcpip_strtoaddr(char *str);\r
1549 \par \r
1550 \par struct netbuf *mosi_strtoaddr(char *str);\r
1551 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The format for TCP/IP addresses is straightforward:\r
1552 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1553 \par <host> [ ':' <portnum> ]\r
1554 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 hostname}{ can be either a domain name or an IP address. The port number, if omitted, defaults to 210.\r
1555 \par For OSI, the format is\r
1556 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1557 \par [ <t-selector> '/' ] <host> [ ':' <port> ]\r
1558 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {The transport selector is given as an even number of hex digits.\r
1559 \par You'll note that the address format for the OSI mode are just a subset of full presentation addresses. We use presentation addresses because xtimosi\r
1560  doesn't, in itself, allow access to the X.500 Directory service. We use a limited form, because we haven't yet come across an implementation that used more of the elements of a full p-address. It is a fairly simple matter to add the rest of the elements \r
1561 to the address format as needed, however: Xtimosi }{\i does}{ support the full P-address structure.\r
1562 \par In both transport modes, the special hostname "@" is mapped to any local address (the manifest constant INADDR_ANY). It is used to establish local listening endpoints in the server role.\r
1563 \par When a connection has been established, you can use\r
1564 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1565 \par char cs_addrstr(COMSTACK h);\r
1566 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1567 to retrieve the host name of the peer system. The function returns a pointer to a static area, which is overwritten on the next call to the function.\r
1568 \par }{\i N\r
1569 OTE: We have left the issue of X.500 name-to-address mapping open, for the moment. It would be a simple matter to provide a table-based mapping, if desired. Alternately, we could use the X.500 client-function that is provided with the ISODE (although this\r
1570  \r
1571 would defeat some of the purpose of using ThinOSI in the first place. We have been told that it should be within the realm of the possible to implement a lightweight implementation of the necessary X.500 client capabilities on top of ThinOSI. This would b\r
1572 e the ideal solution, we feel. On the other hand, it still remains to be seen just what role the Directory will play in a world populated by ThinOSI and other pragmatic solutions.}{\r
1573 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_6}{\*\bkmkstart _Toc399132438}6.6 Diagnostics{\*\bkmkend ss6_6}{\*\bkmkend _Toc399132438}\r
1574 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {All functions return -1 if an error occurs. Typically, the functions will return 0 on success, but the data exchange functions (}{\r
1575 \cs27\f2\fs20 cs_get}{, }{\cs27\f2\fs20 cs_put}{, }{\cs27\f2\fs20 cs_more}{) follow special rules. Consult their descriptions.\r
1576 \par When a function (including the data exchange functions) reports an error condition, use the function }{\cs27\f2\fs20 cs_errno()}{ to determine the cause of the problem. The function\r
1577 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1578 \par void cs_perror(COMSTACK handle char *message);\r
1579 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {works like }{\cs27\f2\fs20 perror}{(2) and prints the }{\cs27\f2\fs20 message}{ argument, along with a system message, to }{\cs27\f2\fs20 \r
1580 stderr}{. Use the character array\r
1581 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1582 \par extern const char *cs_errlist[];\r
1583 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {to get hold of the message, if you want to process it differently. The function\r
1584 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1585 \par const char *cs_stackerr(COMSTACK handle);\r
1586 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Returns an error message from the lower layer, if one has been provided.\r
1587 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_7}{\*\bkmkstart _Toc399132439}6.7 Enabling OSI Communication{\*\bkmkend ss6_7}\r
1588 {\*\bkmkend _Toc399132439}\r
1589 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Installing Xtimosi\r
1590 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\r
1591 Although you will have to download Peter Furniss' XTI/mOSI implementation for yourself, we've tried to make the integration as simple as possible.\r
1592 \par The latest version of xtimosi will generally be under\r
1593 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1594 \par ftp://pluto.ulcc.ac.uk/ulcc/thinosi/xtimosi/\r
1595 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {When you have downloaded and unpacked the archive, it will (we assume) have created a directory called }{\cs27\f2\fs20 xtimosi}{\r
1596 . We suggest that you place this directory }{\i in the same directory}{ where you unpacked the }{\b YAZ}{ distribution. This way, you shouldn't have to fiddle with the makefiles of }{\cs27\f2\fs20 YAZ}{ beyond uncommenting a few lines.\r
1597 \par Go to }{\cs27\f2\fs20 xtimosi/src}{, and type "}{\cs27\f2\fs20 make libmosi.a}{". This should generally create the library, ready to use.\r
1598 \par }{\b CAVEAT}{\r
1599 \par }{\i \r
1600 The currently available release of xtimosi has some inherent problems that make it disfunction on certain platforms - eg. the Digital OSF/1 workstations. It is supposedly primarily a compiler problem, and we hope to see a release that is generally portabl\r
1601 e. While we can't guarantee that it can be brought to work on your platform, we'll be happy to talk to you about problems that you might see, and relay information to the author of the software. There are some signs that the }{\b\i gcc}{\i \r
1602  compiler is more likely to produce a fully functional library, but this hasn't been verified (we think that the problem is limited to the use of hexadecimal escape-codes used in strings, which are silently ignored by some compilers).}{\r
1603 \par }{\i A problem has been encountered in the communication with ISODE-based applications. If the ISODE presentation-user calls }{\cs27\i\f2\fs20 PReadRequest()}{\i  with a timeout value different from }{\cs27\i\f2\fs20 OK}{\i  or }{\cs27\i\f2\fs20 NOTOK}{\r
1604 \i , he will get an immediate TIMEOUT abort when receiving large (>2041 bytes, which is the SPDU-size that the ISODE likes to w\r
1605 ork with) packages from an xtimosi-based implementation (probably most other implementations as well, in fact). It seems to be a flaw in the ISODE API, and the workaround (for ISODE users) is to either not use an explicit timeout (switching to either bloc\r
1606 king or nonblocking mode), or to check that the timer really has expired before closing the connection.}{\r
1607 \par The next step in the installation is to modify the makefile in the toplevel }{\b YAZ}{ directory. The place to change is in the top of the file, and is clearly marked with a comment.\r
1608 \par Now run }{\cs27\f2\fs20 make}{ in the }{\b YAZ}{ toplevel directory (do a "}{\cs27\f2\fs20 make clean}{" first, if the system has been previously made without OSI support). Use the }{\b YAZ}{ }{\b ztest}{ and }{\b client}{\r
1609  demo programs to verify that OSI communication works OK. Then, you can go ahead and try to talk to other implementations.\r
1610 \par }{\i NOTE: Our interoperability experience is limited to version 7 of the Nordic SR-Nett package, which has had several protocol errors fi\r
1611 xed from the earlier releases. If you have problems or successes in interoperating with other implementations, we'd be glad to hear about it, or to help you make things work, as our resources allow.}{\r
1612 \par If you write your own applications based on }{\b YAZ}{, and you wish to include OSI support, the procedure is equally simple. You should include the }{\cs27\f2\fs20 xmosi.h}{ header file in addition to }{\cs27\f2\fs20 comstack.h}{. }{\cs27\f2\fs20 xmosi.h\r
1613 }{ will define the manifest constant }{\cs27\f2\fs20 mosi_type}{, which you should pass to the }{\cs27\f2\fs20 cs_create()}{ function. In addition, you should use the function }{\cs27\f2\fs20 mosi_strtoaddr()}{ rather than }{\cs27\f2\fs20 \r
1614 tcpip_strtoaddr()}{ when you need to prepare an address.\r
1615 \par When you link your application, you should include (after the }{\cs27\f2\fs20 libyaz.a}{ library) the }{\cs27\f2\fs20 libmosi.a}{ library, and the }{\cs27\f2\fs20 librfc.a}{ library provided with }{\b YAZ}{ (for OSI transport).\r
1616 \par As always, it can be very useful, if not essential, to have a look at the example applications to see how things are done.\r
1617 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {OSI Transport\r
1618 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {Xtimosi requires an implementation of the OSI transport service under the X/OPEN XTI API. We provide an\r
1619  implementation of the RFC1006 encapsulation of OSI/TP0 in TCP/IP (through the Berkeley Sockets API), as an independent part of }{\b YAZ}{ (it's found under the }{\cs27\f2\fs20 rfc1006}{\r
1620  directory). If you have access to an OSI transport provider under XTI, you should be able to make that work too, although it may require tinkering with the }{\cs27\f2\fs20 mosi_strtoaddr()}{ function.\r
1621 \par }\pard\plain \s20\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel3\adjustright \b\fs28\lang2057 {Presentation Context Management\r
1622 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {To simplify the implementation, we use Peter Furniss' alternative (PRF) option format for the Control of the presentation negotiation p\r
1623 hase. This format is enabled by default when you compile xtimosi.\r
1624 \par The current version of }{\b YAZ}{ does }{\i not}{ support presentation-layer negotiation of response record formats. The primary reason is that we have had access to no other SR or Z39.50 implementations \r
1625 over OSI that used this method. Secondarily, we believe that the EXPLAIN facility is a superior mechanism for relaying target capabilities in this respect. This is not to say that we have no intentions of supporting presentation context negotiation - we h\r
1626 ave just hitherto given it a lower priority than other aspects of the protocol.\r
1627 \par One thing is certain: The addition of this capability to }{\b YAZ}{ should have only a minimal impact on existing applications, and on the interface to the software in general. Most li\r
1628 kely, we will add an extra layer of interface to the processing of EXPLAIN records, which will convert back and forth between }{\cs27\f2\fs20 oident}{ records (see section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 {\*\datafield \r
1629 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 Object Identifiers}}}{\r
1630 ) and direct or indirect references, given the current association setup. Implementations based on any of the higher-level interfaces will most likely not have to be changed at all.\r
1631 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss6_8}{\*\bkmkstart _Toc399132440}6.8 Summary and Synopsis{\*\bkmkend ss6_8}{\*\bkmkend _Toc399132440}\r
1632 \r
1633 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \f2\fs20\lang2057 {\cs27 \r
1634 \par #include <comstack.h>\r
1635 \par \r
1636 \par #include <tcpip.h>      /* this is for TCP/IP support   */\r
1637 \par #include <xmosi.h>      /* and this is for mOSI support */\r
1638 \par \r
1639 \par COMSTACK cs_create(CS_TYPE type, int blocking, int protocol);\r
1640 \par \r
1641 \par COMSTACK cs_createbysocket(int s, CS_TYPE type, int blocking,\r
1642 \par                               int protocol);\r
1643 \par \r
1644 \par int cs_bind(COMSTACK handle, int mode);\r
1645 \par \r
1646 \par int cs_connect(COMSTACK handle, void *address);\r
1647 \par \r
1648 \par int cs_rcvconnect(COMSTACK handle);\r
1649 \par \r
1650 \par int cs_listen(COMSTACK handle);\r
1651 \par \r
1652 \par COMSTACK cs_accept(COMSTACK handle);\r
1653 \par \r
1654 \par int cs_put(COMSTACK handle, char *buf, int len);\r
1655 \par \r
1656 \par int cs_get(COMSTACK handle, char **buf, int *size);\r
1657 \par \r
1658 \par int cs_more(COMSTACK handle);\r
1659 \par \r
1660 \par int cs_close(COMSTACK handle);\r
1661 \par \r
1662 \par int cs_look(COMSTACK handle);\r
1663 \par \r
1664 \par struct sockaddr_in *tcpip_strtoaddr(char *str);\r
1665 \par \r
1666 \par struct netbuf *mosi_strtoaddr(char *str);\r
1667 \par \r
1668 \par extern int cs_errno;\r
1669 \par \r
1670 \par void cs_perror(COMSTACK handle char *message);\r
1671 \par \r
1672 \par const char *cs_stackerr(COMSTACK handle);\r
1673 \par \r
1674 \par extern const char *cs_errlist[];\r
1675 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart server}{\*\bkmkstart s7}{\*\bkmkend server}\r
1676 \par {\*\bkmkstart _Toc399132441}7. Making an IR Interface for Your Database with YAZ{\*\bkmkend s7}{\*\bkmkend _Toc399132441}\r
1677 \par {\*\bkmkstart ss7_1}{\*\bkmkstart _Toc399132442}7.1 Introduction{\*\bkmkend ss7_1}{\*\bkmkend _Toc399132442}\r
1678 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {\i \r
1679 NOTE: If you aren't into documentation, a good way to learn how the backend interface works is to look at the backend.h file. Then, look at the small dummy-server in server/ztest.c. Finally, you can have a look at the seshigh.c file, which is\r
1680  where most of the logic of the frontend server is located. The backend.h file also makes a good reference, once you've chewed your way through the prose of this file.}{\r
1681 \par If you have a database system that you would like to make available by means of Z39.50/SR, }{\b YAZ}{ basically offers your two options. You can use the APIs provided by the }{\b ASN}{, }{\b ODR}{, and }{\b COMSTACK}{\r
1682  modules to create and decode PDUs, and exchange them with a client. Using this low-level interface gives you access to all fields and options of the proto\r
1683 col, and you can construct your server as close to your existing database as you like. It is also a fairly involved process, requiring you to set up an event-handling mechanism, protocol state machine, etc. To simplify server implementation, we have imple\r
1684 mented a compact and simple, but reasonably full-functioned server-frontend that will handle most of the protocol mechanics, while leaving you to concentrate on your database interface.\r
1685 \par }{\i NOTE: The backend interface was designed in anticipation of a specific \r
1686 integration task, while still attempting to achieve some degree of generality. We realise fully that there are points where the interface can be improved significantly. If you have specific functions or parameters that you think could be useful, send us a\r
1687  mail (or better, sign on to the mailing list referred to in the toplevel README file). We will try to fit good suggestions into future releases, to the extent that it can be done without requiring too many structural changes in existing applications.}{\r
1688 \r
1689 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_2}{\*\bkmkstart _Toc399132443}7.2 The Database Frontend{\*\bkmkend ss7_2}{\*\bkmkend _Toc399132443}\r
1690 \r
1691 \par }\pard\plain \qj\sb100\sa100\nowidctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright \fs22\lang2057 {We refer to this software as a generic database frontend. Your database system is the }{\i backend database}{\r
1692 , and the interface between the two is called the }{\i backend API}{. The backend API consists of a small number of function prototypes and structure definitions. You are required to provide the }{\b main()}{\r
1693  routine for the server (which can be quite simple), as well as functions to match each of the prototypes. The interface functions that you write can use any m\r
1694 echanism you like to communicate with your database system: You might link the whole thing together with your database application and access it by function calls; you might use IPC to talk to a database server somewhere; or you might link with third-part\r
1695 y software that handles the communication for you (like a commercial database client library). At any rate, the functions will perform the tasks of:\r
1696 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Initialization. \r
1697 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Searching. \r
1698 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Fetching records. \r
1699 \par {\pntext\pard\plain\f3\fs22 \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \qj\fi-360\li720\sb100\sa100\nowidctlpar{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnindent360\pnhang{\pntxtb \'b7}}\ls3\adjustright {Scanning the database index (if you wish to impl\r
1700 ement SCAN). \r
1701 \par }\pard \qj\sb100\sa100\nowidctlpar\adjustright {(more functions will be added in time to support as much of Z39.50-1995 as possible).\r
1702 \par Because the model where pipes or sockets are used to access the backend database is a fairly common one, we have added a mechanism that allows this communic\r
1703 ation to take place asynchronously. In this mode, the frontend server doesn't have to block while the backend database is processing a request, but can wait for additional PDUs from the client.\r
1704 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_3}{\*\bkmkstart _Toc399132444}7.3 The Backend API{\*\bkmkend ss7_3}{\*\bkmkend _Toc399132444}\r
1705 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The headers files that you need to use the interface are in the include/ directory. They are called }{\cs27\f2\fs20 statserv.h}{ and }{\cs27\f2\fs20 backend.h}{\r
1706 . They will include other files from the }{\cs27\f2\fs20 include}{ directory, so you'll probably want to use the -I option of your compiler to tell it where to find the files. When you run }{\cs27\f2\fs20 make}{ in the toplevel }{\b YAZ}{\r
1707  directory, everything you need to create your server is put the lib/libyaz.a library. If you want OSI as well, you'll also need to link in the }{\cs27\f2\fs20 libmosi.a}{ library from the xtimosi distribution (see the mosi.txt file), a well as the }{\r
1708 \cs27\f2\fs20 lib/librfc.a}{ library (to provide OSI transport over RFC1006/TCP).\r
1709 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_4}{\*\bkmkstart _Toc399132445}7.4 Your main() Routine{\*\bkmkend ss7_4}{\*\bkmkend _Toc399132445}\r
1710 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {As mentioned, your }{\b main()}{\r
1711  routine can be quite brief. If you want to initialize global parameters, or read global configuration tables, this is the place to do it. At the end of the routine, you should call the function\r
1712 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1713 \par int statserv_main(int argc, char **argv);\r
1714 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b Statserv_main}{ will establish listening sockets according to the parameters given. When connection requests are received, the event handler will typically }{\b fork()}{\r
1715  to handle the new request. If you do use global variables, you should be aware, then, that these cannot be shared\r
1716  between associations, unless you explicitly disallow forking by command line parameters (we advise against this for any purposes except debugging, as a crash or hang in the server process will affect all users currently signed on to the server).\r
1717 \par The server provides a mechanism for controlling some of its behavior without using command-line options. The function\r
1718 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1719 \par statserv_options_block *statserv_getcontrol(void);\r
1720 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Will return a pointer to a }{\cs27\f2\fs20 struct statserv_options_block}{ describing the current default settings of the server. The structure contains these elements:\r
1721 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int dynamic}{\r
1722 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {A boolean value, which determines whether the server will fork on each incoming request (TRUE), or not (FALSE). Default is TRUE.\r
1723 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int loglevel}{\r
1724 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Set this by ORing the constants defined in include/log.h.\r
1725 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char logfile[ODR_MAXNAME+1]}{\r
1726 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {File for diagnostic output ("": stderr).\r
1727 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char apdufile[ODR_MAXNAME+1]}{\r
1728 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Name of file for logging incoming and outgoing APDUs ("": don't log APDUs, "-": }{\cs27\f2\fs20 stderr}{).\r
1729 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char default_listen[1024]}{\r
1730 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1731 Same form as the command-line specification of listener address. "": no default listener address. Default is to listen at "tcp:@:9999". You can only specify one default listener address in this fashion.\r
1732 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b enum oid_proto default_proto;}{\r
1733 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Either }{\cs27\f2\fs20 PROTO_SR}{ or }{\cs27\f2\fs20 PROTO_Z3950}{. Default is }{\cs27\f2\fs20 PROTO_Z39_50}{.\r
1734 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int idle_timeout;}{\r
1735 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum session idletime, in minutes. Zero indicates no (infinite) timeout. Default is 120 minutes.\r
1736 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b int maxrecordsize;}{\r
1737 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum permissible record (message) size. Default is 1Mb. This amount of mem\r
1738 ory will only be allocated if a client requests a very large amount of records in one operation (or a big record). Set it to a lower number if you are worried about resource consumption on your host system.\r
1739 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char configname[ODR_MAXNAME+1]}{\r
1740 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Passed to the backend when a new connection is received.\r
1741 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b char setuid[ODR_MAXNAME+1]}{\r
1742 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Set user id to the user specified, after binding the listener addresses.\r
1743 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The pointer returned by }{\cs27\f2\fs20 statserv_getcontrol}{ points to a static area. You are allowed to change the contents of the st\r
1744 ructure, but the changes will not take effect before you call\r
1745 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1746 \par void statserv_setcontrol(statserv_options_block *block);\r
1747 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Note that you should generally update this structure }{\i before}{ calling }{\cs27\f2\fs20 statserv_main()}{.\r
1748 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_5}{\*\bkmkstart _Toc399132446}7.5 The Backend Functions{\*\bkmkend ss7_5}{\*\bkmkend _Toc399132446}\r
1749 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1750 For each service of the protocol, the backend interface declares one or two functions. You are required to provide implementations of the functions representing the services that you wish to implement.\r
1751 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1752 \par bend_initresult *bend_init(bend_initrequest *r);\r
1753 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1754 This function is called once for each new connection request, after a new process has been forked, and an initRequest has been received from the client. The parameter and result structures are defined as\r
1755 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1756 \par typedef struct bend_initrequest\r
1757 \par \{\r
1758 \par     char *configname;\r
1759 \par \} bend_initrequest;\r
1760 \par \r
1761 \par typedef struct bend_initresult\r
1762 \par \{\r
1763 \par     int errcode;       /* 0==OK */\r
1764 \par     char *errstring;   /* system error string or NULL */\r
1765 \par     void *handle;      /* private handle to the backend module */\r
1766 \par \} bend_initresult;\r
1767 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The }{\cs27\f2\fs20 configname}{ of }{\cs27\f2\fs20 bend_initrequest}{\r
1768  is currently always set to "default-config". We haven't had use for putting anything special in the initrequest yet, but something might go there if the need arises (account/password info would be obvious).\r
1769 \par In general, the server frontend expects that the }{\cs27\f2\fs20 bend_*result}{ pointer that you return is valid at least until the next call to a }{\cs27\f2\fs20 bend_* function}{\r
1770 . This applies to all of the functions described herein. The parameter structure passed to you in\r
1771  the call belongs to the server frontend, and you should not make assumptions about its contents after the current function call has completed. In other words, if you want to retain any of the contents of a request structure, you should copy them.\r
1772 \par The }{\cs27\f2\fs20 errcode}{ should be zero if the initialization of the backend went well. Any other value will be interpreted as an error. The }{\cs27\f2\fs20 errstring}{\r
1773  isn't used in the current version, but one option would be to stick it in the initResponse as a VisibleString. The }{\cs27\f2\fs20 handle}{ is t\r
1774 he most important parameter. It should be set to some value that uniquely identifies the current session to the backend implementation. It is used by the frontend server in any future calls to a backend function. The typical use is to set it to point to a\r
1775  dynamically allocated state structure that is private to your backend module.\r
1776 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1777 \par bend_searchresult *bend_search(void *handle, bend_searchrequest *r,\r
1778 \par                                int *fd);\r
1779 \par bend_searchresult *bend_searchresponse(void *handle);\r
1780 \par \r
1781 \par typedef struct bend_searchrequest\r
1782 \par \{\r
1783 \par     char *setname;       /* name to give to this set */\r
1784 \par     int replace_set;     /* replace set, if it already exists */\r
1785 \par     int num_bases;       /* number of databases in list */\r
1786 \par     char **basenames;    /* databases to search */\r
1787 \par     Z_Query *query;      /* query structure */\r
1788 \par \} bend_searchrequest;\r
1789 \par \r
1790 \par typedef struct bend_searchresult\r
1791 \par \{\r
1792 \par     int hits;            /* number of hits */\r
1793 \par     int errcode;         /* 0==OK */\r
1794 \par     char *errstring;     /* system error string or NULL */\r
1795 \par \} bend_searchresult;\r
1796 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1797 The first thing to notice about the search request interface (as well as all of the following requests), is that it consists of two separate functions. The idea is to provide a simple facility for asynchronous communication with the backend ser\r
1798 ver. When a searchrequest comes in, the server frontend will fill out the }{\cs27\f2\fs20 bend_searchrequest}{ tructure, and call the }{\cs27\f2\fs20 bend_search function}{. The }{\cs27\f2\fs20 fd}{\r
1799  argument will point to an integer variable. If you are able to do asynchronous I/O with your database server, you should set *}{\cs27\f2\fs20 fd}{\r
1800  to the file descriptor you use for the communication, and return a null pointer. The server frontend will then }{\cs27\f2\fs20 select()}{ on the *}{\cs27\f2\fs20 fd}{, and will call }{\cs27\f2\fs20 bend_searchresult}{\r
1801  when it sees that data is available. If you don't support asynchronous I/O, you should return a pointer to the }{\cs27\f2\fs20 bend_searchresult}{ immediately, and leave *}{\cs27\f2\fs20 fd}{ untouched. This construction is common to all of the }{\r
1802 \cs27\f2\fs20 bend_}{ functions (except }{\cs27\f2\fs20 bend_init}{). Note that you can choose to support this facility in none, any, or all of the }{\cs27\f2\fs20 bend_}{ f\r
1803 unctions, and you can respond differently on each request at run-time. The server frontend will adapt accordingly.\r
1804 \par The }{\cs27\f2\fs20 bend_searchrequest}{ is a fairly close approximation of a protocol searchRequest PDU. The }{\cs27\f2\fs20 setname}{ is the resultSetName from the protocol. Y\r
1805 ou are required to establish a mapping between the set name and whatever your backend database likes to use. Similarly, the }{\cs27\f2\fs20 replace_set}{ is a boolean value corresponding to the resultSetIndicator field in the protocol. }{\cs27\f2\fs20 \r
1806 Num_bases/basenames}{ is a length of/array of character pointers to the database names provided by the client. The }{\cs27\f2\fs20 query}{\r
1807  is the full query structure as defined in the protocol ASN.1 specification. It can be either of the possible query types, and it's up to you to determine if\r
1808  you can handle the provided query type. Rather than reproduce the C interface here, we'll refer you to the structure definitions in the file }{\cs27\f2\fs20 include/proto.h}{\r
1809 . If you want to look at the attributeSetId OID of the RPN query, you can either match it against your own internal tables, or you can use the }{\cs27\f2\fs20 oid_getentbyoid}{ function provided by }{\b YAZ}{.\r
1810 \par The result structure contains a number of hits, and an }{\cs27\f2\fs20 errcode/errstring}{ pair. If an error occurs during the search, or if you're unhappy with the request, you should set\r
1811  the errcode to a value from the BIB-1 diagnostic set. The value will then be returned to the user in a nonsurrogate diagnostic record in the response. The }{\cs27\f2\fs20 errstring}{\r
1812 , if provided, will go in the addinfo field. Look at the protocol definition for the defined error codes, and the suggested uses of the addinfo field.\r
1813 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1814 \par bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,\r
1815 \par                              int *fd);\r
1816 \par bend_fetchresult *bend_fetchresponse(void *handle);\r
1817 \par \r
1818 \par typedef struct bend_fetchrequest\r
1819 \par \{\r
1820 \par     char *setname;       /* set name */\r
1821 \par     int number;          /* record number */\r
1822 \par     oid_value format;\r
1823 \par \} bend_fetchrequest;\r
1824 \par \r
1825 \par typedef struct bend_fetchresult\r
1826 \par \{\r
1827 \par     char *basename;      /* name of database that provided record */\r
1828 \par     int len;             /* length of record */\r
1829 \par     char *record;        /* record */\r
1830 \par     int last_in_set;     /* is it?  */\r
1831 \par     oid_value format;\r
1832 \par     int errcode;         /* 0==success */\r
1833 \par     char *errstring;     /* system error string or NULL */\r
1834 \par \} bend_fetchresult;\r
1835 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The }{\cs27\i\f2\fs20 bend_fetchresponse()}{\i  function is not yet supported in this version of the software. Your implementation of }{\cs27\i\f2\fs20 bend_fetch()}{\i \r
1836  should always return a pointer to a }{\cs27\i\f2\fs20 bend_fetchresult}{\i .}{\r
1837 \par The frontend server calls }{\cs27\f2\fs20 bend_fetch}{ when it needs database records to fulfill a searchRequest or a presentRequest. The }{\cs27\f2\fs20 setname}{ is simply the name of the result set that holds the reference to the desired record. The }{\r
1838 \cs27\f2\fs20 number}{ is the offset into the set (with 1 being the first record in the set). The }{\cs27\f2\fs20 format}{ field is the record format requested by the client (See section }{\field{\*\fldinst {HYPERLINK "yaz-3.html" \\l "oid"}{\fs20 \r
1839 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000090000000303000000000000c00000000000004600000b00000079617a2d332e68746d6c00ffffadde000000000000000000000000000000000000000000000000040000006f006900640000000000}}}{\fldrslt {\cs29\ul\cf2 \r
1840 Object Identifiers}}}{). The value }{\cs27\f2\fs20 VAL_NONE}{ indicates that the client did not request a specific format. The }{\cs27\f2\fs20 stream}{ argument is an }{\b ODR}{ stream which should be used for alloc\r
1841 ating space for structured data records. The stream will be reset when all records have been assembled, and the response package has been transmitted. For unstructured data, the backend is responsible for maintaining a static or dynamic buffer for the rec\r
1842 ord between calls.\r
1843 \par In the result structure, the }{\cs27\f2\fs20 basename}{ is the name of the database that holds the record. }{\cs27\f2\fs20 Len}{ is the length of the record returned, in bytes, and }{\cs27\f2\fs20 record}{ is a pointer to the record. }{\cs27\f2\fs20 \r
1844 Last_in_set}{ should be nonzero only if the record returned is the last one in the given result set. }{\cs27\f2\fs20 Errcode}{ and }{\cs27\f2\fs20 errstring}{\r
1845 , if given, will currently be interpreted as a global error pertaining to the set, and will be returned in a nonSurrogateDiagnostic.\r
1846 \par }{\i NOTE: This is silly. Add a flag to say which is which.}{\r
1847 \par If the }{\cs27\f2\fs20 len}{ field has the value -1, then }{\cs27\f2\fs20 record}{ is assumed to point to a constructed data type. The }{\cs27\f2\fs20 format}{ field will be used to determine which encoder should be used to serialize the data.\r
1848 \par }{\i NOTE: If your backend generates structured records, it should use }{\cs27\i\f2\fs20 odr_malloc()}{\i  on the provided stream for allocating data: This allows the frontend server to keep track of the record sizes.}{\r
1849 \par The }{\cs27\f2\fs20 format}{ field is mapped to an object identifier in the direct reference of the resulting EXTERNAL representation of the record.\r
1850 \par }{\i NOTE: The current version of }{\b\i YAZ}{\i  only supports the direct reference mode.}{\r
1851 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1852 \par bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,\r
1853 \par                                int *fd);\r
1854 \par bend_deleteresult *bend_deleteresponse(void *handle);\r
1855 \par \r
1856 \par typedef struct bend_deleterequest\r
1857 \par \{\r
1858 \par     char *setname;\r
1859 \par \} bend_deleterequest;\r
1860 \par \r
1861 \par typedef struct bend_deleteresult\r
1862 \par \{\r
1863 \par     int errcode;         /* 0==success */\r
1864 \par     char *errstring;     /* system error string or NULL */\r
1865 \par \} bend_deleteresult;\r
1866 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The "delete" function is not yet supported in this version of the software.}{\r
1867 \par }{\i NOTE: The delete set function definition is rather primitive, mostly because we have had no practical need for it as of yet. If someone wants to provide a full delete service\r
1868 , we'd be happy to add the extra parameters that are required. Are there clients out there that will actually delete sets they no longer need?}{\r
1869 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1870 \par bend_scanresult *bend_scan(void *handle, bend_scanrequest *r,\r
1871 \par     int *fd);\r
1872 \par bend_scanresult *bend_scanresponse(void *handle);\r
1873 \par \r
1874 \par typedef struct bend_scanrequest\r
1875 \par \{\r
1876 \par     int num_bases;      /* number of elements in databaselist */\r
1877 \par     char **basenames;   /* databases to search */\r
1878 \par     Z_AttributesPlusTerm *term;\r
1879 \par     int term_position;  /* desired index of term in result list */\r
1880 \par     int num_entries;    /* number of entries requested */\r
1881 \par \} bend_scanrequest;\r
1882 \par \r
1883 \par typedef struct bend_scanresult\r
1884 \par \{\r
1885 \par     int num_entries;\r
1886 \par     struct scan_entry\r
1887 \par     \{\r
1888 \par         char *term;\r
1889 \par         int occurrences;\r
1890 \par     \} *entries;\r
1891 \par     int term_position;\r
1892 \par     enum\r
1893 \par     \{\r
1894 \par         BEND_SCAN_SUCCESS,\r
1895 \par         BEND_SCAN_PARTIAL\r
1896 \par     \} status;\r
1897 \par     int errcode;\r
1898 \par     char *errstring;\r
1899 \par \} bend_scanresult;\r
1900 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\i NOTE: The }{\cs27\i\f2\fs20 bend_scanresponse()}{\i  function is not yet supported in this version of the software. Your implementation of }{\cs27\i\f2\fs20 bend_scan()}{\i \r
1901  should always return a pointer to a }{\cs27\i\f2\fs20 bend_scanresult}{\i .}{\r
1902 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_6}{\*\bkmkstart _Toc399132447}7.6 Application Invocation{\*\bkmkend ss7_6}{\*\bkmkend _Toc399132447}\r
1903 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The finished application has the following invocation syntax (by way of }{\cs27\f2\fs20 statserv_main()}{):\r
1904 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1905 \par appname [-szSu -a apdufile -l logfile -v loglevel]\r
1906 \par [listener ...]\r
1907 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The options are\r
1908 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -a}{\r
1909 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {APDU file. Specify a file for dumping PDUs (for diagnostic purposes). The special name "-" sends output to }{\cs27\f2\fs20 stderr}{.\r
1910 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -S}{\r
1911 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Do\r
1912 n't fork on connection requests. This is good for debugging, but not recommended for real operation: Although the server is asynchronous and non-blocking, it can be nice to keep a software malfunction (okay then, a crash) from affecting all current users.\r
1913 \r
1914 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -s}{\r
1915 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Use the SR protocol.\r
1916 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -z}{\r
1917 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1918 Use the Z39.50 protocol (default). These two options complement eachother. You can use both multiple times on the same command line, between listener-specifications (see below). This way, you can set up the server to listen for c\r
1919 onnections in both protocols concurrently, on different local ports.\r
1920 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -l}{\r
1921 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The logfile.\r
1922 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -v}{\r
1923 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The log level. Use a comma-separated list of members of the set \{fatal,debug,warn,log,all,none\}.\r
1924 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -u}{\r
1925 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
1926 Set user ID. Sets the real UID of the server process to that of the given user. It's useful if you aren't comfortable with having the server run as root, but you need to start it as such to bind a privileged port.\r
1927 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -w}{\r
1928 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Working directory.\r
1929 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -i}{\r
1930 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Use this when running from the }{\cs27\f2\fs20 inetd}{ server.\r
1931 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -t}{\r
1932 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Idle session timeout, in minutes.\r
1933 \par }\pard\plain \s15\qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\b -k}{\r
1934 \par }\pard\plain \s16\qj\li360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Maximum record size/message size, in kilobytes.\r
1935 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {A listener specification consists of a transport mode followed by a colon (:) followed by a listener address. The transport mode is either }{\cs27\f2\fs20 osi}{ or }{\cs27\f2\fs20 tcp}{.\r
1936 \r
1937 \par For TCP, an address has the form\r
1938 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1939 \par hostname | IP-number [: portnumber]\r
1940 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The port number defaults to 210 (standard Z39.50 port).\r
1941 \par For osi, the address form is\r
1942 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1943 \par [t-selector /] hostname | IP-number [: portnumber]\r
1944 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The transport selector is given as a string of hex digits (with an even number of digits). The default port number is 102 (RFC1006 port).\r
1945 \par Examples\r
1946 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1947 \par tcp:dranet.dra.com\r
1948 \par \r
1949 \par osi:0402/dbserver.osiworld.com:3000\r
1950 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {In both cases, the special hostname "@" is mapped to the address INADDR_ANY, which causes \r
1951 the server to listen on any local interface. To start the server listening on the registered ports for Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the ports are bound, execute the server like this (from a root shell):\r
1952 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1953 \par my-server -u daemon tcp:@ -s osi:@\r
1954 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {You can replace }{\cs27\f2\fs20 daemon}{ with another user, eg. your own account, or a dedicated IR server account. }{\cs27\f2\fs20 my-server}{\r
1955  should be the name of your server application. You can test the procedure with the }{\cs27\f2\fs20 ztest}{ application.\r
1956 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss7_7}{\*\bkmkstart _Toc399132448}7.7 Summary and Synopsis{\*\bkmkend ss7_7}{\*\bkmkend _Toc399132448}\r
1957 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
1958 \par #include <backend.h>\r
1959 \par \r
1960 \par bend_initresult *bend_init(bend_initrequest *r);\r
1961 \par \r
1962 \par bend_searchresult *bend_search(void *handle, bend_searchrequest *r,\r
1963 \par                                  int *fd);\r
1964 \par \r
1965 \par bend_searchresult *bend_searchresponse(void *handle);\r
1966 \par \r
1967 \par bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *r,\r
1968 \par                                int *fd);\r
1969 \par \r
1970 \par bend_fetchresult *bend_fetchresponse(void *handle);\r
1971 \par \r
1972 \par bend_scanresult *bend_scan(void *handle, bend_scanrequest *r, int *fd);\r
1973 \par \r
1974 \par bend_scanresult *bend_scanresponse(void *handle);\r
1975 \par \r
1976 \par bend_deleteresult *bend_delete(void *handle, bend_deleterequest *r,\r
1977 \par                                   int *fd);\r
1978 \par \r
1979 \par bend_deleteresult *bend_deleteresponse(void *handle);\r
1980 \par \r
1981 \par void bend_close(void *handle);\r
1982 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s8}\r
1983 \par {\*\bkmkstart _Toc399132449}8. Future Directions{\*\bkmkend s8}{\*\bkmkend _Toc399132449}\r
1984 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The software has been successfully ported to the Mac as well as Windows NT/95 - we'd like to test those ports better and make sure they work as they should.\r
1985 \par We have a new and better version of the frontend server on the drawing board. Resources and external commitments will govern when we'll be able to do something real with it. Fetures should include greater flexibility, greter support for access/resource co\r
1986 ntrol, and easy support for Explain (possibly with Zebra as an extra database engine).\r
1987 \par We now support all PDUs of Z39.50-1995. If there is one of the supporting structures that you need but can't find in the prt*.h files, send us a note; it may be on its way.\r
1988 \par The 'retrieval' module needs to be finalized and documented. We think it can form a useful resource for people dealing with complex record structures, but for now, you'll mostly have to chew through the code yourself to make use of it. Not acceptable.\r
1989 \r
1990 \par O\r
1991 ther than that, YAZ generally moves in the directions which appear to make the most people happy (including ourselves, as prime users of the software). If there's something you'd like to see in here, then drop us a note and let's see what we can come up w\r
1992 ith.\r
1993 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s9}{\*\bkmkstart _Toc399132450}9. License{\*\bkmkend s9}{\*\bkmkend _Toc399132450}\r
1994 \par {\*\bkmkstart ss9_1}{\*\bkmkstart _Toc399132451}9.1 Index Data Copyright{\*\bkmkend ss9_1}{\*\bkmkend _Toc399132451}\r
1995 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Copyright (c) 1995,1996 Index Data.\r
1996 \par Permission to use, copy, modify, distribute, and sell this software and its documentation, in whole or in part, for any purpose, is hereby granted, provided that:\r
1997 \par 1. This copyright and permission notice appear in all copies of the software and its documentation. Notices of copyright or attribution which appear at the beginning of any file must remain unchanged.\r
1998 \par 2. The names of Index Data or the individual authors may not be used to endorse or promote products derived from this software without specific prior written permission.\r
1999 \par THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED, OR OTH\r
2000 ERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTI\r
2001 NG FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
2002 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart ss9_2}{\*\bkmkstart _Toc399132452}9.2 Additional Copyright Statements{\*\bkmkend ss9_2}{\*\bkmkend _Toc399132452}\r
2003 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {The optional CCL query language interpreter is covered by the following license:\r
2004 \par Copyright (c) 1995, the EUROPAGATE consortium (see below).\r
2005 \par The EUROPAGATE consortium members are:\r
2006 \par University College Dublin Danmarks Teknologiske Videnscenter An Chomhairle Leabharlanna Consejo Superior de Investigaciones Cientificas\r
2007 \par Permission to use, copy, modify, distribute, and sell this software and its documentation, in whole or in part, for any purpose, is hereby granted, provided that:\r
2008 \par 1. This copyright and permission notice appear in all copies of the software and its documentation. Notices of copyright or attribution which appear at the beginning of any file must remain unchanged.\r
2009 \par 2. The names of EUROPAGATE or the project partners may not be used to endorse or promote products derived from this software without specific prior written permission.\r
2010 \par 3. Users of this software (implementors and gateway operators) agree to inform the EUROPAGATE consortium of their use of the software. This information will be u\r
2011 sed to evaluate the EUROPAGATE project and the software, and to plan further developments. The consortium may use the information in later publications.\r
2012 \par 4. Users of this software agree to make their best efforts, when documenting their use of the software, to acknowledge the EUROPAGATE consortium, and the role played by the software in their work.\r
2013 \par THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY \r
2014 OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WH\r
2015 ETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
2016 \par }\pard\plain \s19\qj\sb100\sa100\keepn\nowidctlpar\outlinelevel2\adjustright \b\fs36\lang2057 {{\*\bkmkstart s10}{\*\bkmkstart _Toc399132453}10. About Index Data{\*\bkmkend s10}{\*\bkmkend _Toc399132453}\r
2017 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {Index Data is a consulting and software-dev\r
2018 elopment enterprise that specialises in library and information management systems. Our interests and expertise span a broad range of related fields, and one of our primary, long-term objectives is the development of a powerful information management syst\r
2019 em with open network interfaces and hypermedia capabilities.\r
2020 \par We make this software available free of charge, on a fairly unrestrictive license; as a service to the networking community, and to further the development of quality software for open network communication.\r
2021 \par We'll be happy to answer questions about the software, and about ourselves in general.\r
2022 \par }\pard\plain \s25\qj\li360\ri360\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\cs27\f2\fs20 Index Data\line Ryesgade 3\line DK-2200 K\'f8benhavn N}{\r
2023 \par }\pard\plain \s32\qj\li360\ri360\nowidctlpar\tx0\tx959\tx1918\tx2877\tx3836\tx4795\tx5754\tx6713\tx7672\tx8631\adjustright \f2\fs20\lang2057 {\cs27 \r
2024 \par Phone: +45 3536 3672\r
2025 \par Fax  : +45 3536 0449\r
2026 \par Email: info@index.ping.dk\r
2027 \par }\pard\plain \qj\sb100\sa100\nowidctlpar\adjustright \fs22\lang2057 {\r
2028 \par }}