File CODE_STYLE added (mode: 100644) (index 0000000..9677131) |
|
1 |
|
=============================================================================== |
|
2 |
|
|
|
3 |
|
- Suckless code style |
|
4 |
|
https://suckless.org/coding_style/ |
|
5 |
|
|
|
6 |
|
- Splint (linter) |
|
7 |
|
https://splint.org/ |
|
8 |
|
|
|
9 |
|
=============================================================================== |
|
10 |
|
|
|
11 |
|
Style |
|
12 |
|
|
|
13 |
|
Note that the following are guidelines and the most important aspect of style is consistency. Strive to keep your style consistent with the project on which you are working. It is up to the project maintainer to take some liberty in the style guidelines. |
|
14 |
|
Recommended Reading |
|
15 |
|
|
|
16 |
|
The following contain good information, some of which is repeated below, some of which is contradicted below. |
|
17 |
|
|
|
18 |
|
https://man.openbsd.org/style |
|
19 |
|
http://doc.cat-v.org/bell_labs/pikestyle |
|
20 |
|
https://www.kernel.org/doc/Documentation/process/coding-style.rst |
|
21 |
|
|
|
22 |
|
File Layout |
|
23 |
|
|
|
24 |
|
Comment with LICENSE and possibly short explanation of file/tool. |
|
25 |
|
Headers |
|
26 |
|
Macros |
|
27 |
|
Types |
|
28 |
|
Function declarations: |
|
29 |
|
Include variable names. |
|
30 |
|
For short files these can be left out. |
|
31 |
|
Group/order in logical manner. |
|
32 |
|
Global variables. |
|
33 |
|
Function definitions in same order as declarations. |
|
34 |
|
main |
|
35 |
|
|
|
36 |
|
C Features |
|
37 |
|
|
|
38 |
|
Use C99 without extensions (ISO/IEC 9899:1999). |
|
39 |
|
Use POSIX.1-2008: |
|
40 |
|
When using gcc define _POSIX_C_SOURCE 200809L. |
|
41 |
|
Alternatively define _XOPEN_SOURCE 700. |
|
42 |
|
Do not mix declarations and code. |
|
43 |
|
Do not use for loop initial declarations. |
|
44 |
|
Use /* */ for comments, not //. |
|
45 |
|
Variadic macros are acceptable, but remember: |
|
46 |
|
__VA_ARGS__ not a named parameter. |
|
47 |
|
Arg list cannot be empty. |
|
48 |
|
|
|
49 |
|
Blocks |
|
50 |
|
|
|
51 |
|
All variable declarations at top of block. |
|
52 |
|
{ on same line preceded by single space (except functions). |
|
53 |
|
} on own line unless continuing statement (if else, do while, ...). |
|
54 |
|
|
|
55 |
|
Use block for single statement if inner statement needs a block. |
|
56 |
|
|
|
57 |
|
for (;;) { |
|
58 |
|
if (foo) { |
|
59 |
|
bar; |
|
60 |
|
baz; |
|
61 |
|
} |
|
62 |
|
} |
|
63 |
|
|
|
64 |
|
Use another branch of the same statement needs a block: |
|
65 |
|
|
|
66 |
|
if (foo) { |
|
67 |
|
bar; |
|
68 |
|
} else { |
|
69 |
|
baz; |
|
70 |
|
qux; |
|
71 |
|
} |
|
72 |
|
|
|
73 |
|
Leading Whitespace |
|
74 |
|
|
|
75 |
|
Use tabs for indentation and spaces for alignment. This ensures everything will line up independent of tab size. This means: |
|
76 |
|
|
|
77 |
|
No tabs except beginning of line. |
|
78 |
|
Use spaces - not tabs - for multiline macros as the indentation level is 0, where the #define began. |
|
79 |
|
|
|
80 |
|
Functions |
|
81 |
|
|
|
82 |
|
Return type and modifiers on own line. |
|
83 |
|
Function name and argument list on next line. This allows to grep for function names simply using grep ^functionname(. |
|
84 |
|
Opening { on own line (function definitions are a special case of blocks as they cannot be nested). |
|
85 |
|
Functions not used outside translation unit should be declared and defined static. |
|
86 |
|
|
|
87 |
|
Example: |
|
88 |
|
|
|
89 |
|
static void |
|
90 |
|
usage(void) |
|
91 |
|
{ |
|
92 |
|
eprintf("usage: %s [file ...]\n", argv0); |
|
93 |
|
} |
|
94 |
|
|
|
95 |
|
Variables |
|
96 |
|
|
|
97 |
|
Global variables not used outside translation unit should be declared static. |
|
98 |
|
In declaration of pointers the * is adjacent to variable name, not type. |
|
99 |
|
|
|
100 |
|
Keywords |
|
101 |
|
|
|
102 |
|
Use a space after if, for, while, switch (they are not function calls). |
|
103 |
|
Do not use a space after the opening ( and before the closing ). |
|
104 |
|
Preferably use () with sizeof. |
|
105 |
|
Do not use a space with sizeof(). |
|
106 |
|
|
|
107 |
|
Switch |
|
108 |
|
|
|
109 |
|
Do not indent cases another level. |
|
110 |
|
Comment cases that FALLTHROUGH. |
|
111 |
|
|
|
112 |
|
Example: |
|
113 |
|
|
|
114 |
|
switch (value) { |
|
115 |
|
case 0: /* FALLTHROUGH */ |
|
116 |
|
case 1: |
|
117 |
|
case 2: |
|
118 |
|
break; |
|
119 |
|
default: |
|
120 |
|
break; |
|
121 |
|
} |
|
122 |
|
|
|
123 |
|
Headers |
|
124 |
|
|
|
125 |
|
Place system/libc headers first in alphabetical order. |
|
126 |
|
If headers must be included in a specific order add a comment to explain. |
|
127 |
|
Place local headers after an empty line. |
|
128 |
|
When writing and using local headers. |
|
129 |
|
Try to avoid cyclic header inclusion dependencies. |
|
130 |
|
Instead ensure they are included where and when they are needed. |
|
131 |
|
Read https://talks.golang.org/2012/splash.article#TOC_5. |
|
132 |
|
Read http://plan9.bell-labs.com/sys/doc/comp.html |
|
133 |
|
|
|
134 |
|
User Defined Types |
|
135 |
|
|
|
136 |
|
Do not use type_t naming (it is reserved for POSIX and less readable). |
|
137 |
|
Typedef opaque structs. |
|
138 |
|
Do not typedef builtin types. |
|
139 |
|
Use CamelCase for typedef'd types. |
|
140 |
|
|
|
141 |
|
Line Length |
|
142 |
|
|
|
143 |
|
Keep lines to reasonable length (max 79 characters). |
|
144 |
|
|
|
145 |
|
Tests and Boolean Values |
|
146 |
|
|
|
147 |
|
Do not use C99 bool types (stick to integer types). |
|
148 |
|
Otherwise use compound assignment and tests unless the line grows too long: |
|
149 |
|
|
|
150 |
|
if (!(p = malloc(sizeof(*p)))) |
|
151 |
|
hcf(); |
|
152 |
|
|
|
153 |
|
Handling Errors |
|
154 |
|
|
|
155 |
|
When functions return -1 for error test against 0 not -1: |
|
156 |
|
|
|
157 |
|
if (func() < 0) |
|
158 |
|
hcf(); |
|
159 |
|
|
|
160 |
|
Use goto to unwind and cleanup when necessary instead of multiple nested levels. |
|
161 |
|
return or exit early on failures instead of multiple nested levels. |
|
162 |
|
Unreachable code should have a NOTREACHED comment. |
|
163 |
|
Think long and hard on whether or not you should cleanup on fatal errors. For simple "one-shot" programs (not daemons) it can be OK to not free memory. It is advised to cleanup temporary files however. |
|
164 |
|
|
|
165 |
|
Enums and #define |
|
166 |
|
|
|
167 |
|
Use enums for values that are grouped semantically and #define otherwise: |
|
168 |
|
|
|
169 |
|
#define MAXSZ 4096 |
|
170 |
|
#define MAGIC1 0xdeadbeef |
|
171 |
|
|
|
172 |
|
enum { |
|
173 |
|
DIRECTION_X, |
|
174 |
|
DIRECTION_Y, |
|
175 |
|
DIRECTION_Z |
|
176 |
|
}; |
File LICENSE added (mode: 100644) (index 0000000..fcc2ca6) |
|
1 |
|
MIT License |
|
2 |
|
|
|
3 |
|
Copyright (c) 2019 Suckless Islamic |
|
4 |
|
|
|
5 |
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
6 |
|
of this software and associated documentation files (the "Software"), to deal |
|
7 |
|
in the Software without restriction, including without limitation the rights |
|
8 |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
|
copies of the Software, and to permit persons to whom the Software is |
|
10 |
|
furnished to do so, subject to the following conditions: |
|
11 |
|
|
|
12 |
|
The above copyright notice and this permission notice shall be included in all |
|
13 |
|
copies or substantial portions of the Software. |
|
14 |
|
|
|
15 |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
16 |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
17 |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
18 |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
19 |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
20 |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
21 |
|
SOFTWARE. |
File azan.c added (mode: 100644) (index 0000000..5cccd7d) |
|
1 |
|
/* See LICENSE file for copyright and license details. |
|
2 |
|
* Azan is simple Muslim prayers notifier. |
|
3 |
|
* print next pray left duration. |
|
4 |
|
* |
|
5 |
|
* use curl lib to make a get request to azan api |
|
6 |
|
* save json file in /tmp dir |
|
7 |
|
* each time app runs check if cache file exists if not make get request |
|
8 |
|
* |
|
9 |
|
* read the cache file, get next pray, print left duration %h:%m |
|
10 |
|
* send notification if left duration = 0 minutes |
|
11 |
|
* |
|
12 |
|
* this app should run each 59s |
|
13 |
|
*/ |
|
14 |
|
|
|
15 |
|
#include <stdio.h> |
|
16 |
|
#include <time.h> |
|
17 |
|
#include <string.h> |
|
18 |
|
#include <sys/stat.h> |
|
19 |
|
#include <curl/curl.h> |
|
20 |
|
#include <json-c/json.h> |
|
21 |
|
|
|
22 |
|
#include "azan.h" |
|
23 |
|
#include "config.h" |
|
24 |
|
|
|
25 |
|
static int |
|
26 |
|
file_exist(char *filename) |
|
27 |
|
{ |
|
28 |
|
struct stat buffer; |
|
29 |
|
return (stat(filename, &buffer) == 0); |
|
30 |
|
} |
|
31 |
|
|
|
32 |
|
static void |
|
33 |
|
get_page(const char* url, const char* file_name) |
|
34 |
|
{ |
|
35 |
|
|
|
36 |
|
// Check connection |
|
37 |
|
CURL *curl = curl_easy_init(); |
|
38 |
|
if(curl) { |
|
39 |
|
CURLcode ret; |
|
40 |
|
curl_easy_setopt(curl, CURLOPT_URL, "https://google.com/"); |
|
41 |
|
// curl_easy_setopt(curl, CURLOPT_URL, "test a failed connection"); |
|
42 |
|
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); |
|
43 |
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L); |
|
44 |
|
ret = curl_easy_perform(curl); |
|
45 |
|
|
|
46 |
|
// If Connected |
|
47 |
|
if(ret == CURLE_OK) { |
|
48 |
|
CURL* easyhandle = curl_easy_init(); |
|
49 |
|
curl_easy_setopt(easyhandle, CURLOPT_URL, url); |
|
50 |
|
FILE* file = fopen(file_name, "w"); |
|
51 |
|
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, file) ; |
|
52 |
|
curl_easy_perform(easyhandle); |
|
53 |
|
curl_easy_cleanup(easyhandle); |
|
54 |
|
fclose(file); |
|
55 |
|
} |
|
56 |
|
|
|
57 |
|
// If Not Connected |
|
58 |
|
else{ |
|
59 |
|
printf("not connected\n"); |
|
60 |
|
} |
|
61 |
|
} |
|
62 |
|
} |
|
63 |
|
|
|
64 |
|
static void |
|
65 |
|
print_next_pray(time_t t, char *json_file) |
|
66 |
|
{ |
|
67 |
|
|
|
68 |
|
/* this fuction get as argument a json file |
|
69 |
|
opens it and find pray times data |
|
70 |
|
create a local array to store data |
|
71 |
|
assign data to array |
|
72 |
|
|
|
73 |
|
TODO: |
|
74 |
|
1- return values as time type |
|
75 |
|
2- pass an array insted of creating local one and no return |
|
76 |
|
*/ |
|
77 |
|
|
|
78 |
|
// Parse the json file |
|
79 |
|
FILE *fp; |
|
80 |
|
char buffer[2048]; |
|
81 |
|
|
|
82 |
|
fp = fopen(json_file,"r"); |
|
83 |
|
fread(buffer, 2048, 1, fp); |
|
84 |
|
fclose(fp); |
|
85 |
|
|
|
86 |
|
struct json_object *parsed_json; |
|
87 |
|
struct json_object *data; |
|
88 |
|
struct json_object *timings; |
|
89 |
|
|
|
90 |
|
struct json_object *date; |
|
91 |
|
struct json_object *json_hijri; |
|
92 |
|
struct json_object *json_date; |
|
93 |
|
|
|
94 |
|
// typedef struct { |
|
95 |
|
// const struct json_object *json_pray; |
|
96 |
|
// const char *string_pray; |
|
97 |
|
// const unsigned int int_pray; |
|
98 |
|
// const time_t time_pray; |
|
99 |
|
// }PrayTime; |
|
100 |
|
|
|
101 |
|
struct json_object *json_pray[5]; |
|
102 |
|
const char *array_string_pray[5]; |
|
103 |
|
int array_array_int_pray[5][2]; |
|
104 |
|
time_t array_time_pray[6]; |
|
105 |
|
char array_char_pray_name[6] = {'F','D','A','M','I','F'}; |
|
106 |
|
|
|
107 |
|
parsed_json = json_tokener_parse(buffer); |
|
108 |
|
json_object_object_get_ex(parsed_json, "data" , &data); |
|
109 |
|
json_object_object_get_ex(data, "timings", &timings); |
|
110 |
|
|
|
111 |
|
json_object_object_get_ex(data, "date", &date); |
|
112 |
|
json_object_object_get_ex(date, "hijri", &json_hijri); |
|
113 |
|
json_object_object_get_ex(json_hijri, "date", &json_date); |
|
114 |
|
|
|
115 |
|
// Hijri date |
|
116 |
|
const char *hijri = json_object_get_string(json_date); |
|
117 |
|
|
|
118 |
|
json_object_object_get_ex(timings, "Fajr", &json_pray[0]); |
|
119 |
|
json_object_object_get_ex(timings, "Dhuhr", &json_pray[1]); |
|
120 |
|
json_object_object_get_ex(timings, "Asr", &json_pray[2]); |
|
121 |
|
json_object_object_get_ex(timings, "Maghrib", &json_pray[3]); |
|
122 |
|
json_object_object_get_ex(timings, "Isha", &json_pray[4]); |
|
123 |
|
|
|
124 |
|
// Handel time and duration |
|
125 |
|
// struct tm current_time = *localtime(&t); |
|
126 |
|
struct tm dt = *localtime(&t); |
|
127 |
|
|
|
128 |
|
for(int i = 0; i < 5; i++){ |
|
129 |
|
// Create array of strings from the json object |
|
130 |
|
array_string_pray[i] = json_object_get_string(json_pray[i]), |
|
131 |
|
|
|
132 |
|
// Remove : from string parsed from json file |
|
133 |
|
// Add to pray_int array |
|
134 |
|
sscanf(array_string_pray[i], "%d:%d", |
|
135 |
|
&array_array_int_pray[i][0], &array_array_int_pray[i][1]); |
|
136 |
|
|
|
137 |
|
// Change the hours and minutes from int array to time type |
|
138 |
|
dt.tm_hour = array_array_int_pray[i][0]; |
|
139 |
|
dt.tm_min = array_array_int_pray[i][1]; |
|
140 |
|
array_time_pray[i] = mktime(&dt); |
|
141 |
|
}; |
|
142 |
|
|
|
143 |
|
// Create next fajr |
|
144 |
|
dt.tm_mday = dt.tm_mday+1; |
|
145 |
|
dt.tm_hour = array_array_int_pray[0][0]; |
|
146 |
|
dt.tm_min = array_array_int_pray[0][1]; |
|
147 |
|
array_time_pray[5] = mktime(&dt); |
|
148 |
|
|
|
149 |
|
for(int i=0; i<6; i++){ |
|
150 |
|
if(t == array_time_pray[i]){ |
|
151 |
|
printf("%*.*s 00:00\n", 5, 5, hijri); |
|
152 |
|
char command[100], msg[100]; |
|
153 |
|
strcpy(command,"notify-send "); |
|
154 |
|
strcpy(msg,"\"Azan\""); |
|
155 |
|
strcat(command,msg); |
|
156 |
|
(void) system(command); |
|
157 |
|
break; |
|
158 |
|
} |
|
159 |
|
else if(t < array_time_pray[i]){ |
|
160 |
|
// duration to next pray |
|
161 |
|
int seconds = difftime(array_time_pray[i], t); |
|
162 |
|
unsigned int hours = (seconds / (60*60)); |
|
163 |
|
unsigned int minutes = (seconds / (60)) % 60; |
|
164 |
|
|
|
165 |
|
printf("%*.*s %c %.2d:%.2d\n", 5, 5, hijri, |
|
166 |
|
array_char_pray_name[i], hours, minutes); break; |
|
167 |
|
}; |
|
168 |
|
}; |
|
169 |
|
|
|
170 |
|
//struct tm tm; |
|
171 |
|
// char buf[255]; |
|
172 |
|
// |
|
173 |
|
// strptime("2001-11-13 18:31:01", "%Y-%m-%d %H:%M:%S", &tm); |
|
174 |
|
// strftime(buf, sizeof(buf), "%s", &tm); |
|
175 |
|
// puts(buf); |
|
176 |
|
// exit(EXIT_SUCCESS); |
|
177 |
|
} |
|
178 |
|
|
|
179 |
|
int |
|
180 |
|
main(void) |
|
181 |
|
{ |
|
182 |
|
time_t t = time(NULL); |
|
183 |
|
struct tm tm_variable = *localtime(&t); |
|
184 |
|
|
|
185 |
|
// Cache file name |
|
186 |
|
static char cache_file[32]; |
|
187 |
|
sprintf(cache_file, "/tmp/%.2d-%.2d-%d.json", |
|
188 |
|
tm_variable.tm_mday, tm_variable.tm_mon+1, |
|
189 |
|
tm_variable.tm_year+1900); |
|
190 |
|
|
|
191 |
|
// Chech if cache does not exists |
|
192 |
|
if (!file_exist (cache_file)){ |
|
193 |
|
static char api_url[128]; |
|
194 |
|
sprintf(api_url, |
|
195 |
|
"http://api.aladhan.com/v1/timingsByCity?city=%s&country=%s&method=8", |
|
196 |
|
city, country); |
|
197 |
|
|
|
198 |
|
// Create the cache file |
|
199 |
|
get_page(api_url, cache_file); |
|
200 |
|
} |
|
201 |
|
|
|
202 |
|
// Read if exists cache file and print next pray left time |
|
203 |
|
if (file_exist (cache_file)){ |
|
204 |
|
print_next_pray(t, cache_file); |
|
205 |
|
} |
|
206 |
|
return 0; |
|
207 |
|
} |