0 #include "scheme.h"

1 #include "gemini.h"

2 #include "cert.h"

3 #include <tinyscheme/scheme.h>

4 #include <tinyscheme/scheme-private.h>

5 #include <time.h>

6 #include <string.h>

7 #include <stdlib.h>

8 #include <pthread.h>

9

10 pointer unix_sec(scheme *sc, pointer args) {

11 if (args != sc->NIL) {

12 // error

13 return sc->F;

14 }

15 return mk_integer(sc, time(NULL));

16 }

17

18 pointer set_element_text(scheme *sc, pointer args) {

19 int i = 0;

20 char* id = NULL;

21 char* str_value = NULL;

22 while (args != sc->NIL) {

23 pointer arg;

24 if (i == 0 && is_string(arg = pair_car(args))) {

25 id = string_value(arg);

26 } else if (i == 1) {

27 struct gmi_tab* tab = NULL;

28 for (int i=0; i < client.tabs_count; i++) {

29 if (client.tabs[i].ctx == sc) {

30 tab = &client.tabs[i];

31 break;

32 }

33 }

34 if (!tab) return sc->F;

35 if (is_string(arg = pair_car(args)))

36 str_value = string_value(arg);

37 else if (is_integer(arg = pair_car(args))) {

38 char buf[32];

39 if (is_real(arg))

40 snprintf(buf, sizeof(buf), "%!f(MISSING)", rvalue(arg));

41 else

42 snprintf(buf, sizeof(buf), "%!l(MISSING)d", ivalue(arg));

43 str_value = string_value(mk_string(sc, buf));

44 } else

45 return sc->F;

46

47 for (int i = 0; i < tab->page.objs_count; i++) {

48 if (!strcmp(tab->page.objs[i].id, id)) {

49 tab->page.objs[i].value = str_value;

50 client.refresh = 1;

51 return sc->T;

52 }

53 }

54

55 return sc->F;

56 } else

57 return sc->F;

58 args = pair_cdr(args);

59 i++;

60 }

61 return sc->F;

62 }

63

64 struct ffunction {

65 pointer (*func)(scheme*, pointer);

66 const char* name;

67 };

68

69 struct interval {

70 long msec;

71 pointer lambda;

72 struct timespec called;

73 long id;

74 int active;

75 struct gmi_tab* tab;

76 };

77

78 struct interval intervals[1024];

79 int interval_counts = 0;

80

81 void* interval_thread(void* ptr) {

82 while (!client.shutdown) {

83 struct timespec current;

84 for (int i = 0; i < interval_counts; i++) {

85 struct interval* iv = &intervals[i];

86 if (!iv->active) continue;

87 clock_gettime(CLOCK_MONOTONIC_RAW, &current);

88 if (((current.tv_sec - iv->called.tv_sec)*1000000000 +

89 current.tv_nsec - iv->called.tv_nsec)/1000000 > iv->msec) {

90 pointer args =

91 cons(iv->tab->ctx,

92 mk_integer(iv->tab->ctx, iv->id),

93 iv->tab->ctx->NIL);

94 scheme_call(iv->tab->ctx, iv->lambda, args);

95 clock_gettime(CLOCK_MONOTONIC_RAW, &iv->called);

96 }

97 }

98 struct timespec ts = {0, 1000000};

99 nanosleep(&ts, NULL);

100 }

101 return ptr;

102 }

103

104 pointer interval(scheme *sc, pointer args) {

105 int i = 0;

106 int msec = 0;

107 while (args != sc->NIL) {

108 pointer arg;

109 if (i == 0 && is_integer(arg = pair_car(args))) {

110 msec = rvalue(arg);

111 }

112 else if (i == 1 && is_closure(arg = pair_car(args))) {

113 struct interval* iv = &intervals[interval_counts];

114 iv->lambda = arg;

115 iv->msec = msec;

116 iv->active = 1;

117 iv->tab = NULL;

118 for (int i=0; i < client.tabs_count; i++) {

119 if (client.tabs[i].ctx == sc) {

120 iv->tab = &client.tabs[i];

121 break;

122 }

123 }

124 if (!iv->tab) return sc->F;

125 clock_gettime(CLOCK_MONOTONIC_RAW, &iv->called);

126 interval_counts++;

127 return mk_integer(sc, interval_counts-1);

128 } else

129 return sc->F;

130 args = pair_cdr(args);

131 i++;

132 }

133 return sc->F;

134 }

135

136 pointer interval_stop(scheme *sc, pointer args) {

137 pointer arg;

138 if (!is_integer(arg = pair_car(args))) {

139 // error

140 return sc->F;

141 }

142 long id = rvalue(arg);

143 if (id >= (signed)sizeof(intervals)) {

144 // error

145 return sc->F;

146 }

147 intervals[id].active = 0;

148 return sc->T;

149 }

150

151 struct ffunction functions[] = {

152 {unix_sec, "unix-sec"},

153 {interval, "interval"},

154 {interval_stop, "stop-interval"},

155 {set_element_text, "set-element-text"}

156 };

157

158 pthread_t interval_t;

159 int scm_init() {

160 return pthread_create(&interval_t, NULL, (void *(*)(void*))interval_thread, NULL);

161 }

162

163 int scm_free() {

164 return pthread_join(interval_t, NULL);

165 }

166

167 int scm_init_tab(struct gmi_tab* tab) {

168 if (tab->ctx) scheme_deinit(tab->ctx);

169 tab->ctx = scheme_init_new();

170 char buf[1024];

171

172 int len = getcachefolder(buf, sizeof(buf));

173 snprintf(&buf[len], sizeof(buf)-len, "/output_%!p(MISSING).log", (void*)tab);

174 FILE* f = fopen(buf, "w");

175 if (f)

176 scheme_set_output_port_file(tab->ctx, f);

177

178 for (size_t i=0; i < sizeof(functions)/sizeof(struct ffunction); i++)

179 scheme_define(

180 tab->ctx,

181 tab->ctx->global_env,

182 mk_symbol(tab->ctx, functions[i].name),

183 mk_foreign_func(tab->ctx, functions[i].func));

184

185 return 0;

186 }

187