OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE.md file. | |
4 | |
5 #include <stdio.h> | |
6 #include <pthread.h> | |
7 #include <stdlib.h> | |
8 | |
9 #include "include/dartino_api.h" | |
10 #include "include/service_api.h" | |
11 #include "generated/cc/simple_todo.h" | |
12 | |
13 static const int kDone = 1; | |
14 static pthread_mutex_t mutex; | |
15 static pthread_cond_t cond; | |
16 static int status = 0; | |
17 | |
18 typedef enum { | |
19 EC_OK = 0, | |
20 EC_THREAD, | |
21 EC_INPUT_ERR, | |
22 } ErrorCode; | |
23 | |
24 static void ChangeStatusAndNotify(int new_status) { | |
25 pthread_mutex_lock(&mutex); | |
26 status = new_status; | |
27 pthread_cond_signal(&cond); | |
28 pthread_mutex_unlock(&mutex); | |
29 } | |
30 | |
31 static void WaitForVmThread(int expected) { | |
32 pthread_mutex_lock(&mutex); | |
33 while (expected != status) pthread_cond_wait(&cond, &mutex); | |
34 pthread_mutex_unlock(&mutex); | |
35 } | |
36 | |
37 static void* StartDartino(void* arg) { | |
38 char* snapshot_filepath_with_name = reinterpret_cast<char*>(arg); | |
39 DartinoSetup(); | |
40 DartinoProgram program = | |
41 DartinoLoadSnapshotFromFile(snapshot_filepath_with_name); | |
42 if (DartinoRunMain(program, 0, NULL) != 0) { | |
43 printf("Failed to run snapshot: %s\n", snapshot_filepath_with_name); | |
44 exit(1); | |
45 } | |
46 DartinoDeleteProgram(program); | |
47 DartinoTearDown(); | |
48 ChangeStatusAndNotify(kDone); | |
49 return NULL; | |
50 } | |
51 | |
52 static void StartVmThread(char* snapshot_filename) { | |
53 pthread_mutex_init(&mutex, NULL); | |
54 pthread_cond_init(&cond, NULL); | |
55 pthread_t tid = 0; | |
56 int result = pthread_create(&tid, 0, StartDartino, | |
57 reinterpret_cast<void*>(snapshot_filename)); | |
58 if (result != 0) { | |
59 printf("Error creating thread\n"); | |
60 exit(EC_THREAD); | |
61 } | |
62 } | |
63 | |
64 class TodoListView { | |
65 public: | |
66 void showMenu() { | |
67 printf("\n #### Todo Menu ####\n" | |
68 "m\t-show this menu\n" | |
69 "l\t-list todo items\n" | |
70 "a\t-add todo item\n" | |
71 "t\t-toggle todo item done/undone\n" | |
72 "c\t-clear done items\n" | |
73 "d\t-delete item\n" | |
74 "q\t-quit application\n"); | |
75 } | |
76 | |
77 int readln(char* buffer, int buffer_length) { | |
78 int i = 0; | |
79 int ch = 0; | |
80 | |
81 if ((buffer == NULL) || (buffer_length == 0)) return 0; | |
82 | |
83 do { | |
84 ch = getchar(); | |
85 if (ch != EOF && ch != '\n') { | |
86 buffer[i] = ch; | |
87 } | |
88 | |
89 if (ch == EOF) return -1; | |
90 | |
91 ++i; | |
92 } while (ch != '\n' && i < buffer_length); | |
93 buffer[i] = 0; | |
94 return i; | |
95 } | |
96 | |
97 // TODO(zarah): In a multithreaded setting this should be atomic or extend | |
98 // the service with a List<Item> getItems to use here instead. | |
99 void listTodoItems() { | |
100 int32_t count = TodoService::getNoItems(); | |
101 int32_t i = 0; | |
102 | |
103 printf("-------------------- ToDo's --------------------\n"); | |
104 printf("Listing %2u items\n", count); | |
105 for (i = 0; i < count; ++i) { | |
106 TodoItem item = TodoService::getItem(i); | |
107 const char* done = (item.getDone() ? "+" : " "); | |
108 printf("%2u: %s [%1s] \n", item.getId(), item.getTitle(), done); | |
109 } | |
110 printf("------------------------------------------------\n"); | |
111 } | |
112 | |
113 void addTodoItem() { | |
114 char title[60] = {0}; | |
115 int title_length = sizeof(title); | |
116 printf("Add Todo Item:\n"); | |
117 printf("Title: "); | |
118 title_length = readln(title, title_length); | |
119 printf("\n"); | |
120 | |
121 int size = 56 + BoxString::kSize + title_length; | |
122 MessageBuilder builder(size); | |
123 BoxStringBuilder box = builder.initRoot<BoxStringBuilder>(); | |
124 box.setS(title); | |
125 TodoService::createItem(box); | |
126 } | |
127 | |
128 void toggleTodoItem() { | |
129 char idstr[5] = {0}; | |
130 printf("[t] Enter id: "); | |
131 readln(idstr, sizeof(idstr)); | |
132 printf("%s\n", idstr); | |
133 TodoService::toggle(atoi(idstr)); | |
134 } | |
135 | |
136 void clear_done_items() { | |
137 TodoService::clearItems(); | |
138 } | |
139 | |
140 void deleteItem() { | |
141 char idstr[5] = {0}; | |
142 printf("[d] Enter id: "); | |
143 readln(idstr, sizeof(idstr)); | |
144 printf("%s\n", idstr); | |
145 TodoService::deleteItem(atoi(idstr)); | |
146 } | |
147 }; | |
148 | |
149 static int InteractWithService() { | |
150 TodoService::setup(); | |
151 ErrorCode ec = EC_OK; | |
152 TodoListView view; | |
153 view.showMenu(); | |
154 bool should_terminate = false; | |
155 do { | |
156 char in[2] = {0}; | |
157 if (view.readln(in, 2) < 0) { | |
158 ec = EC_OK; | |
159 should_terminate = true; | |
160 } else { | |
161 printf("\n"); | |
162 switch (in[0]) { | |
163 case 'q': | |
164 should_terminate = true; | |
165 break; | |
166 case 'm': | |
167 view.showMenu(); | |
168 break; | |
169 case 'l': | |
170 view.listTodoItems(); | |
171 break; | |
172 case 'a': | |
173 view.addTodoItem(); | |
174 view.listTodoItems(); | |
175 break; | |
176 case 't': | |
177 view.toggleTodoItem(); | |
178 view.listTodoItems(); | |
179 break; | |
180 case 'c': | |
181 view.clear_done_items(); | |
182 view.listTodoItems(); | |
183 break; | |
184 case 'd': | |
185 view.deleteItem(); | |
186 view.listTodoItems(); | |
187 break; | |
188 default: | |
189 break; | |
190 } | |
191 } | |
192 } while (!should_terminate); | |
193 TodoService::tearDown(); | |
194 return ec; | |
195 } | |
196 | |
197 int main(int argc, char** argv) { | |
198 if (argc < 2) { | |
199 printf("Usage: %s <snapshot file>\n", argv[0]); | |
200 return EC_OK; | |
201 } | |
202 | |
203 ServiceApiSetup(); | |
204 StartVmThread(argv[1]); | |
205 int ec = InteractWithService(); | |
206 WaitForVmThread(kDone); | |
207 return ec; | |
208 } | |
OLD | NEW |