source: mainline/uspace/app/contacts/contacts.c@ 7b87e1d

lfn serial ticket/834-toolchain-update topic/fix-logger-deadlock topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7b87e1d was 9c5e3a5, checked in by Jiri Svoboda <jiri@…>, 8 years ago

SIF node unmarshalling.

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2018 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup contacts
30 * @{
31 */
32
33/**
34 * @file Contact list application.
35 *
36 * Maintain a contact list / address book. The main purpose of this
37 * trivial application is to serve as an example of using SIF.
38 */
39
40#include <adt/list.h>
41#include <errno.h>
42#include <nchoice.h>
43#include <sif.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <str.h>
47
48/** Contacts */
49typedef struct {
50 /** Open SIF repository */
51 sif_sess_t *repo;
52 /** Entries SIF node */
53 sif_node_t *nentries;
54 /** Entries list (of contacts_entry_t) */
55 list_t entries;
56} contacts_t;
57
58/** Contact entry */
59typedef struct {
60 /** Link to contacts_t.entries */
61 link_t lentries;
62} contacts_entry_t;
63
64/** Actions in contact menu */
65typedef enum {
66 /** Create new contact */
67 ac_create_contact,
68 /** Delete contact */
69 ac_delete_contact,
70 /** Exit */
71 ac_exit
72} contact_action_t;
73
74/** Open contacts repo or create it if it does not exist.
75 *
76 * @param fname File name
77 * @param rcontacts Place to store pointer to contacts object.
78 *
79 * @return EOK on success or error code
80 */
81static errno_t contacts_open(const char *fname, contacts_t **rcontacts)
82{
83 contacts_t *contacts = NULL;
84 sif_sess_t *repo = NULL;
85 sif_trans_t *trans = NULL;
86 sif_node_t *node;
87 const char *ntype;
88 errno_t rc;
89
90 contacts = calloc(1, sizeof(contacts_t));
91 if (contacts == NULL)
92 return ENOMEM;
93
94 list_initialize(&contacts->entries);
95
96 /* Try to open an existing repository. */
97 rc = sif_open(fname, &repo);
98 if (rc != EOK) {
99 /* Failed to open existing, create new repository */
100 rc = sif_create(fname, &repo);
101 if (rc != EOK)
102 goto error;
103
104 /* Start a transaction */
105 rc = sif_trans_begin(repo, &trans);
106 if (rc != EOK)
107 goto error;
108
109 /* Create 'entries' node container for all entries */
110 rc = sif_node_append_child(trans, sif_get_root(repo), "entries",
111 &contacts->nentries);
112 if (rc != EOK)
113 goto error;
114
115 /* Finish the transaction */
116 rc = sif_trans_end(trans);
117 if (rc != EOK)
118 goto error;
119
120 trans = NULL;
121 } else {
122 /*
123 * Opened an existing repository. Find the 'entries' node.
124 * It should be the very first child of the root node.
125 * This is okay to do in general, as long as we don't
126 * require forward compatibility (which we don't).
127 */
128 node = sif_node_first_child(sif_get_root(repo));
129 if (node == NULL) {
130 rc = EIO;
131 goto error;
132 }
133
134 /* Verify it's the correct node type(!) */
135 ntype = sif_node_get_type(node);
136 if (str_cmp(ntype, "entries") != 0) {
137 rc = EIO;
138 goto error;
139 }
140
141 contacts->nentries = node;
142 }
143
144 contacts->repo = repo;
145 *rcontacts = contacts;
146
147 return EOK;
148error:
149 if (trans != NULL)
150 sif_trans_abort(trans);
151 if (repo != NULL)
152 (void) sif_close(repo);
153 if (contacts != NULL)
154 free(contacts);
155 return rc;
156}
157
158/** Interaction to create new contact.
159 *
160 * @param contacts Contacts
161 */
162static errno_t contacts_create_contact(contacts_t *contacts)
163{
164 tinput_t *tinput;
165 sif_trans_t *trans = NULL;
166 sif_node_t *nentry;
167 errno_t rc;
168 char *cname = NULL;
169
170 tinput = tinput_new();
171 if (tinput == NULL)
172 return ENOMEM;
173
174 printf("Contact name:\n");
175
176 rc = tinput_set_prompt(tinput, "?> ");
177 if (rc != EOK)
178 goto error;
179
180 rc = tinput_read(tinput, &cname);
181 if (rc != EOK)
182 goto error;
183
184 rc = sif_trans_begin(contacts->repo, &trans);
185 if (rc != EOK)
186 goto error;
187
188 rc = sif_node_append_child(trans, contacts->nentries, "entry", &nentry);
189 if (rc != EOK)
190 goto error;
191
192 rc = sif_node_set_attr(trans, nentry, "name", cname);
193 if (rc != EOK)
194 goto error;
195
196 rc = sif_trans_end(trans);
197 if (rc != EOK)
198 goto error;
199
200 trans = NULL;
201
202 free(cname);
203 tinput_destroy(tinput);
204 return EOK;
205error:
206 if (trans != NULL)
207 sif_trans_abort(trans);
208 if (cname != NULL)
209 free(cname);
210 return rc;
211}
212
213/** Interaction to delete contact.
214 *
215 * @param contacts Contacts
216 */
217static errno_t contacts_delete_contact(contacts_t *contacts)
218{
219 return EOK;
220}
221
222/** Close contacts repo.
223 *
224 * @param contacts Contacts
225 */
226static void contacts_close(contacts_t *contacts)
227{
228 printf("Closing repo %p\n", contacts->repo);
229 sif_close(contacts->repo);
230 free(contacts);
231}
232
233/** Run contacts main menu.
234 *
235 * @param contacts Contacts
236 * @return EOK on success or error code
237 */
238static errno_t contacts_main(contacts_t *contacts)
239{
240 nchoice_t *choice = NULL;
241 errno_t rc;
242 bool quit = false;
243 void *sel;
244
245 rc = nchoice_create(&choice);
246 if (rc != EOK) {
247 assert(rc == ENOMEM);
248 printf("Out of memory.\n");
249 goto error;
250 }
251
252 rc = nchoice_set_prompt(choice, "Select action");
253 if (rc != EOK) {
254 assert(rc == ENOMEM);
255 printf("Out of memory.\n");
256 goto error;
257 }
258
259 rc = nchoice_add(choice, "Create contact",
260 (void *)ac_create_contact, 0);
261 if (rc != EOK) {
262 assert(rc == ENOMEM);
263 printf("Out of memory.\n");
264 goto error;
265 }
266
267 rc = nchoice_add(choice, "Delete contact",
268 (void *)ac_delete_contact, 0);
269 if (rc != EOK) {
270 assert(rc == ENOMEM);
271 printf("Out of memory.\n");
272 goto error;
273 }
274
275 rc = nchoice_add(choice, "Exit",
276 (void *)ac_exit, 0);
277 if (rc != EOK) {
278 assert(rc == ENOMEM);
279 printf("Out of memory.\n");
280 goto error;
281 }
282
283 while (!quit) {
284 rc = nchoice_get(choice, &sel);
285 if (rc != EOK) {
286 printf("Error getting user selection.\n");
287 return rc;
288 }
289
290 switch ((contact_action_t)sel) {
291 case ac_create_contact:
292 (void) contacts_create_contact(contacts);
293 break;
294 case ac_delete_contact:
295 (void) contacts_delete_contact(contacts);
296 break;
297 case ac_exit:
298 quit = true;
299 break;
300 }
301 }
302
303 nchoice_destroy(choice);
304 return EOK;
305error:
306 if (choice != NULL)
307 nchoice_destroy(choice);
308 return rc;
309}
310
311int main(void)
312{
313 errno_t rc;
314 contacts_t *contacts;
315
316 rc = contacts_open("contacts.sif", &contacts);
317 if (rc != EOK)
318 return 1;
319
320 rc = contacts_main(contacts);
321 contacts_close(contacts);
322
323 if (rc != EOK)
324 return 1;
325
326 return 0;
327}
Note: See TracBrowser for help on using the repository browser.