Mercurial > urweb
comparison src/c/urweb.c @ 425:7009b0ac1501
Properly freeing libpq results on errors
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Fri, 24 Oct 2008 17:30:07 -0400 |
parents | b91480c9a729 |
children | 2a861b56969c |
comparison
equal
deleted
inserted
replaced
424:b10132434adc | 425:7009b0ac1501 |
---|---|
13 | 13 |
14 typedef struct regions { | 14 typedef struct regions { |
15 struct regions *next; | 15 struct regions *next; |
16 } regions; | 16 } regions; |
17 | 17 |
18 typedef struct { | |
19 void (*func)(void*); | |
20 void *arg; | |
21 } cleanup; | |
22 | |
18 struct uw_context { | 23 struct uw_context { |
19 char *page, *page_front, *page_back; | 24 char *page, *page_front, *page_back; |
20 char *heap, *heap_front, *heap_back; | 25 char *heap, *heap_front, *heap_back; |
21 char **inputs; | 26 char **inputs; |
22 | 27 |
24 | 29 |
25 jmp_buf jmp_buf; | 30 jmp_buf jmp_buf; |
26 | 31 |
27 regions *regions; | 32 regions *regions; |
28 | 33 |
34 cleanup *cleanup, *cleanup_front, *cleanup_back; | |
35 | |
29 char error_message[ERROR_BUF_LEN]; | 36 char error_message[ERROR_BUF_LEN]; |
30 }; | 37 }; |
31 | 38 |
32 extern int uw_inputs_len; | 39 extern int uw_inputs_len; |
33 | 40 |
43 ctx->inputs = calloc(uw_inputs_len, sizeof(char *)); | 50 ctx->inputs = calloc(uw_inputs_len, sizeof(char *)); |
44 | 51 |
45 ctx->db = NULL; | 52 ctx->db = NULL; |
46 | 53 |
47 ctx->regions = NULL; | 54 ctx->regions = NULL; |
55 | |
56 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0); | |
48 | 57 |
49 ctx->error_message[0] = 0; | 58 ctx->error_message[0] = 0; |
50 | 59 |
51 return ctx; | 60 return ctx; |
52 } | 61 } |
61 | 70 |
62 void uw_free(uw_context ctx) { | 71 void uw_free(uw_context ctx) { |
63 free(ctx->page); | 72 free(ctx->page); |
64 free(ctx->heap); | 73 free(ctx->heap); |
65 free(ctx->inputs); | 74 free(ctx->inputs); |
75 free(ctx->cleanup); | |
66 free(ctx); | 76 free(ctx); |
67 } | 77 } |
68 | 78 |
69 void uw_reset_keep_request(uw_context ctx) { | 79 void uw_reset_keep_request(uw_context ctx) { |
70 ctx->page_front = ctx->page; | 80 ctx->page_front = ctx->page; |
71 ctx->heap_front = ctx->heap; | 81 ctx->heap_front = ctx->heap; |
72 ctx->regions = NULL; | 82 ctx->regions = NULL; |
83 ctx->cleanup_front = ctx->cleanup; | |
73 | 84 |
74 ctx->error_message[0] = 0; | 85 ctx->error_message[0] = 0; |
75 } | 86 } |
76 | 87 |
77 void uw_reset_keep_error_message(uw_context ctx) { | 88 void uw_reset_keep_error_message(uw_context ctx) { |
78 ctx->page_front = ctx->page; | 89 ctx->page_front = ctx->page; |
79 ctx->heap_front = ctx->heap; | 90 ctx->heap_front = ctx->heap; |
80 ctx->regions = NULL; | 91 ctx->regions = NULL; |
92 ctx->cleanup_front = ctx->cleanup; | |
81 } | 93 } |
82 | 94 |
83 void uw_reset(uw_context ctx) { | 95 void uw_reset(uw_context ctx) { |
84 uw_reset_keep_request(ctx); | 96 uw_reset_keep_request(ctx); |
85 memset(ctx->inputs, 0, uw_inputs_len * sizeof(char *)); | 97 memset(ctx->inputs, 0, uw_inputs_len * sizeof(char *)); |
105 | 117 |
106 return r; | 118 return r; |
107 } | 119 } |
108 | 120 |
109 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) { | 121 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) { |
122 cleanup *cl; | |
123 | |
110 va_list ap; | 124 va_list ap; |
111 va_start(ap, fmt); | 125 va_start(ap, fmt); |
112 | 126 |
113 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); | 127 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); |
114 | 128 |
129 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl) | |
130 cl->func(cl->arg); | |
131 | |
132 ctx->cleanup_front = ctx->cleanup; | |
133 | |
115 longjmp(ctx->jmp_buf, fk); | 134 longjmp(ctx->jmp_buf, fk); |
135 } | |
136 | |
137 void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) { | |
138 if (ctx->cleanup_front >= ctx->cleanup_back) { | |
139 int len = ctx->cleanup_back - ctx->cleanup, newLen; | |
140 if (len == 0) | |
141 newLen = 1; | |
142 else | |
143 newLen *= 2; | |
144 ctx->cleanup = realloc(ctx->cleanup, newLen); | |
145 ctx->cleanup_front = ctx->cleanup + len; | |
146 ctx->cleanup_back = ctx->cleanup + newLen; | |
147 } | |
148 | |
149 ctx->cleanup_front->func = func; | |
150 ctx->cleanup_front->arg = arg; | |
151 ++ctx->cleanup_front; | |
152 } | |
153 | |
154 void uw_pop_cleanup(uw_context ctx) { | |
155 if (ctx->cleanup_front == ctx->cleanup) | |
156 uw_error(ctx, FATAL, "Attempt to pop from empty cleanup action stack"); | |
157 | |
158 --ctx->cleanup_front; | |
159 ctx->cleanup_front->func(ctx->cleanup_front->arg); | |
116 } | 160 } |
117 | 161 |
118 char *uw_error_message(uw_context ctx) { | 162 char *uw_error_message(uw_context ctx) { |
119 return ctx->error_message; | 163 return ctx->error_message; |
120 } | 164 } |