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