1 /* Copyright (C) 2016-2017 Shengyu Zhang <i@silverrainz.me>
2 *
3 * This file is part of Srain.
4 *
5 * Srain is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * @file ret.c
21 * @brief Srain return value, which can carry message
22 * @author Shengyu Zhang <i@silverrainz.me>
23 * @version 0.06.2
24 * @date 2017-07-13
25 */
26
27 #include <glib.h>
28
29 #include "i18n.h"
30 #include "ret.h"
31 #include "log.h"
32
33 #define SRN_RET_MESSAGE_COUNT 512
34
35 typedef struct _SrnRetMessage SrnRetMessage;
36
37 struct _SrnRetMessage {
38 SrnRet id;
39 int no;
40 char *msg;
41 };
42
43 static SrnRet msgid = 0;
44 static GList *msg_list = NULL;
45 static GMutex mutex;
46
47 static SrnRetMessage* srn_ret_message_new(SrnRet id, int no, const char *msg);
48 static void srn_ret_message_free(SrnRetMessage *rmsg);
49 static SrnRet ret_with_message(int no, const char *fmt, va_list ap);
50
ret_init()51 void ret_init(){
52 g_mutex_init(&mutex);
53 }
54
ret_finalize()55 void ret_finalize(){
56 g_list_free_full(msg_list, (GDestroyNotify)srn_ret_message_free);
57 }
58
ret_err(const char * fmt,...)59 SrnRet ret_err(const char *fmt, ...){
60 SrnRet id;
61 va_list args;
62
63 va_start(args, fmt);
64 id = ret_with_message(SRN_ERR, fmt, args);
65 va_end(args);
66
67 return id;
68 }
69
ret_ok(const char * fmt,...)70 SrnRet ret_ok(const char *fmt, ...){
71 SrnRet id;
72 va_list args;
73
74 va_start(args, fmt);
75 id = ret_with_message(SRN_OK, fmt, args);
76 va_end(args);
77
78 return id;
79 }
80
ret_get_message(SrnRet id)81 const char *ret_get_message(SrnRet id){
82 const char *msg;
83 GList *lst;
84 SrnRetMessage *err;
85
86 g_mutex_lock(&mutex);
87
88 msg = NULL;
89
90 if (id == SRN_OK) {
91 goto fin;
92 }
93 if (id == SRN_ERR) {
94 msg = _("Some error occurred");
95 goto fin;
96 }
97
98 lst = msg_list;
99 while (lst){
100 err = lst->data;
101
102 if (err->id == id) {
103 msg = err->msg;
104 break;
105 }
106 lst = g_list_next(lst);
107 }
108
109 fin:
110 g_mutex_unlock(&mutex);
111 if (id != SRN_OK && !msg){
112 msg = _("Invalid error id, maybe this error is removed because out of date");
113 }
114
115 return msg;
116 }
117
ret_get_no(SrnRet id)118 int ret_get_no(SrnRet id){
119 int no;
120 GList *lst;
121 SrnRetMessage *rmsg;
122
123 no = SRN_ERR;
124 g_mutex_lock(&mutex);
125
126 if (id == SRN_OK || id == SRN_ERR){
127 no = id;
128 goto fin;
129 }
130
131 rmsg = NULL;
132 lst = msg_list;
133 while (lst){
134 rmsg = lst->data;
135 if (rmsg->id == id) {
136 no = rmsg->no;
137 break;
138 }
139 lst = g_list_next(lst);
140 }
141
142 fin:
143 g_mutex_unlock(&mutex);
144 return no;
145 }
146
ret_with_message(int no,const char * fmt,va_list ap)147 static SrnRet ret_with_message(int no, const char *fmt, va_list ap){
148 GString *msg;
149 SrnRetMessage *rmsg;
150
151 g_mutex_lock(&mutex);
152
153 if (g_list_length(msg_list) > SRN_RET_MESSAGE_COUNT){
154 // If msg_list full
155 GList *last;
156 last = g_list_last(msg_list);
157 srn_ret_message_free((SrnRetMessage *)last->data);
158 msg_list = g_list_delete_link(msg_list, last);
159 }
160
161 msg = g_string_new(NULL);
162 g_string_append_vprintf(msg, fmt, ap);
163
164 rmsg = srn_ret_message_new(++msgid, no, msg->str);
165 g_string_free(msg, TRUE);
166
167 msg_list = g_list_prepend(msg_list, rmsg);
168
169 g_mutex_unlock(&mutex);
170
171 return rmsg->id;
172 }
173
srn_ret_message_new(SrnRet id,int no,const char * msg)174 static SrnRetMessage* srn_ret_message_new(SrnRet id, int no, const char *msg){
175 SrnRetMessage *rmsg;
176
177 rmsg = g_malloc0(sizeof(SrnRetMessage));
178 rmsg->id = id;
179 rmsg->no = no;
180 rmsg->msg = g_strdup(msg);
181
182 DBG_FR("SrnRet: id: %d, no: %d, msg: %s", id, no, msg);
183
184 return rmsg;
185 }
186
srn_ret_message_free(SrnRetMessage * rmsg)187 static void srn_ret_message_free(SrnRetMessage *rmsg){
188 g_free(rmsg->msg);
189 g_free(rmsg);
190 }
191