aboutsummaryrefslogtreecommitdiffstats
path: root/doc/get-started.tex
blob: bbf62e0a2c559fc69abbc9221cfda2a764c42514 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
\chapter{Get started}
\label{chap:Get started}

In this chapter, you will learn the basics of libzahl.
You should read the sections in order.

\vspace{1cm}
\minitoc


% TODO add a section a linking and stuff here.


\newpage
\section{Initialisation}
\label{sec:Initialisation}

Before using libzahl, it must be initialised. When
initialising, you must select a location whither libzahl
long jumps on error.

\begin{alltt}
   #include <zahl.h>

   int
   main(void)
   \{
       jmp_buf jmpenv;
       if (setjmp(jmpenv))
           return 1; \textcolor{c}{/* \textrm{Exit on error} */}
       zsetup(jmpenv);
       \textcolor{c}{/* \textrm{\ldots} */}
       return 0;
   \}
\end{alltt}

{\tt zsetup} also initialises temporary variables used
by libzahl's functions, and constants used by libzahl's
functions. Furthermore, it initialises the memory pool
and a stack which libzahl uses to keep track of temporary
allocations that need to be pooled for use if a function
fails.

It is recommended to also uninitialise libzahl when you
are done using it, for example before the program exits.

\begin{alltt}
   \textcolor{c}{int
   main(void)
   \{
       jmp_buf jmpenv;
       if (setjmp(jmpenv))
           return 1; /* \textrm{Exit on error} */
       zsetup(jmpenv);
       /* \textrm{\ldots} */}
       zunsetup();
       \textcolor{c}{return 0;
   \}}
\end{alltt}

{\tt zunsetup} all memory that has been reclaimed to
the memory pool, and all memory allocated by {\tt zsetup}.
Note that this does not free integers that are still
in use. It is possible to simply call {\tt zunsetup}
directly followed by {\tt zsetup} to free all pooled
memory.


\newpage
\section{Exceptional conditions}
\label{sec:Exceptional conditions}

Exceptional conditions, casually called `errors',
are treated in libzahl using long jumps.

\begin{alltt}
   int
   main(int argc, char *argv[])
   \{
       jmp_buf jmpenv;
       if (setjmp(jmpenv))
           return 1; \textcolor{c}{/* \textrm{Exit on error} */}
       zsetup(jmpenv);
       return 0;
   \}
\end{alltt}

Just exiting on error is not a particularly good
idea. Instead, you may want to print an error message.
This is done with {\tt zperror}.

\begin{alltt}
   if (setjmp(jmpenv)) \{
       zperror(\textcolor{c}{*argv});
       \textcolor{c}{return 1;}
   \}
\end{alltt}

\noindent
{\tt zperror} works just like {\tt perror}. It
outputs an error description to standard error.
A line break is printed at the end of the message.
If the argument passed to {\tt zperror} is neither
{\tt NULL} nor an empty string, it is printed in
front of the description, with a colon and a
space separating the passed string and the description.
For example, {\tt zperror("my-app")} may output

\begin{verbatim}
   my-app: Cannot allocate memory
\end{verbatim}

libzahl also provides {\tt zerror}. Calling this
function will provide you with an error code and
a textual description.

\begin{alltt}
   \textcolor{c}{if (setjmp(jmpenv)) \{}
       const char *description;
       zerror(&description);
       fprintf(stderr, "\%s: \%s\verb|\|n", *argv, description);
       \textcolor{c}{return 1;}
   \textcolor{c}{\}}
\end{alltt}

\noindent
This code behaves like the example above that
calls {\tt zperror}. If you are interested in the
error code, you instead look at the return value.

\begin{alltt}
   \textcolor{c}{if (setjmp(jmpenv)) \{}
       enum zerror e = zerror(NULL);
       switch (e) \{
       case ZERROR_ERRNO_SET:
           perror("");
           \textcolor{c}{return 1;}
       case ZERROR_0_POW_0:
           fprintf(stderr, "Indeterminate form: 0^0\verb|\|n");
           \textcolor{c}{return 1;}
       case ZERROR_0_DIV_0:
           fprintf(stderr, "Indeterminate form: 0/0\verb|\|n");
           \textcolor{c}{return 1;}
       case ZERROR_DIV_0:
           fprintf(stderr, "Do not divide by zero, dummy\verb|\|n");
           \textcolor{c}{return 1;}
       case ZERROR_NEGATIVE:
           fprintf(stderr, "Undefined (negative input)\verb|\|n");
           \textcolor{c}{return 1;}
       default:
           zperror("");
           \textcolor{c}{return 1;}
       \}
   \textcolor{c}{\}}
\end{alltt}

To change the point whither libzahl's functions
jump, call {\tt setjmp} and {\tt zsetup} again.

\begin{alltt}
   jmp_buf jmpenv;
   if (setjmp(jmpenv)) \{
       \textcolor{c}{/* \textrm{\ldots} */}
   \}
   zsetup(jmpenv);
   \textcolor{c}{/* \textrm{\ldots} */}
   if (setjmp(jmpenv)) \{
       \textcolor{c}{/* \textrm{\ldots} */}
   \}
   zsetup(jmpenv);
\end{alltt}


\newpage
\section{Create an integer}
\label{sec:Create an integer}

To do any real work with libzahl, we need integers. The
data type for a big integer in libzahl is {\tt z\_t}
\psecref{sec:Integer structure}. Before a {\tt z\_t}
can be assign a value, it must be initialised.

\begin{alltt}
   z_t a;
   \textcolor{c}{/* \textrm{\ldots} */
   zsetup(jmpenv);}
   zinit(a);
   \textcolor{c}{/* \textrm{\ldots} */
   zunsetup();}
\end{alltt}

\noindent
{\tt zinit(a)} is actually a less cumbersome and optimised
alternative to calling {\tt memset(a, 0, sizeof(z\_t))}.
It sets the values of two members: {\tt .alloced} and
{\tt .chars}, to 0 and {\tt NULL}. This is necessary,
otherwise the memory allocated could be fooled to deallocate
a false pointer, causing the program to abort.

Once the reference has been initialised, you may assign it
a value. The simplest way to do this is by calling

\begin{alltt}
   void zseti(z_t a, int64_t value);
\end{alltt}

\noindent
For example {\tt zseti(a, 1)}, assignes the value 1 to
the {\tt z\_t} {\tt a}.

When you are done using a big integer reference, you should
call {\tt zfree} to let libzahl know that it should pool
the allocation of the {\tt .chars} member.

\begin{alltt}
   z_t a;
   zinit(a);
   \textcolor{c}{/* \textrm{\ldots} */}
   zfree(a); \textcolor{c}{/* \textrm{before \texttt{zunsetup}} */}
\end{alltt}

\noindent
Instead of calling {\tt zfree(a)}, it is possible — but
strongly discouraged — to call {\tt free(a->chars)}.
Note however, by doing so, the allocation is not pooled
for reuse.

If you plan to reuse the variable later, you need to
reinitialise it by calling {\tt zinit} again.

Alternatives to {\tt zseti} include:

\begin{alltt}
   void zsetu(z_t a, uint64_t value);
   void zsets(z_t a, const char *value);
   void zset(z_t a, z_t value); \textcolor{c}{/* \textrm{copy \texttt{value} into \texttt{a}} */}
\end{alltt}