NetSurf
misc.c
Go to the documentation of this file.
1/*
2 * Copyright 2008-2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf 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#include <stdlib.h>
20#include <string.h>
21#include <sys/stat.h>
22
23#include <proto/dos.h>
24#include <proto/exec.h>
25#include <proto/utility.h>
26
27#ifndef __amigaos4__
28#include <proto/intuition.h> // for EasyRequest
29#endif
30
31#include "utils/utils.h"
32#include "utils/corestrings.h"
33#include "utils/log.h"
34#include "utils/file.h"
35#include "utils/messages.h"
36#include "utils/nsurl.h"
37#include "utils/url.h"
38
39#include "netsurf/window.h"
40
41#include "amiga/gui.h"
42#include "amiga/misc.h"
43#include "amiga/utf8.h"
44
45static LONG ami_misc_req(const char *message, uint32 type)
46{
47 LONG ret = 0;
49
50 NSLOG(netsurf, INFO, "%s", message);
51#ifdef __amigaos4__
52 ret = TimedDosRequesterTags(
53 TDR_TitleString, messages_get("NetSurf"),
54 TDR_FormatString, message,
55 TDR_GadgetString, messages_get("OK"),
56 TDR_ImageType, type,
57 TDR_Window, cur_gw ? ami_gui_get_window(cur_gw) : NULL,
58 TAG_DONE);
59#else
60 struct EasyStruct easyreq = {
61 sizeof(struct EasyStruct),
62 0,
63 messages_get("NetSurf"),
64 message,
65 messages_get("OK"),
66 };
67
68 ret = EasyRequest(cur_gw ? ami_gui_get_window(cur_gw) : NULL, &easyreq, NULL);
69#endif
70 return ret;
71}
72
73void ami_misc_fatal_error(const char *message)
74{
76}
77
78/* exported interface documented in amiga/misc.h */
79nserror amiga_warn_user(const char *warning, const char *detail)
80{
81 char *utf8warning = ami_utf8_easy(messages_get(warning));
82 STRPTR bodytext = ASPrintf("\33b%s\33n\n%s",
83 utf8warning != NULL ? utf8warning : warning, detail);
84
86
87 if(bodytext) FreeVec(bodytext);
88 if(utf8warning) free(utf8warning);
89
90 return NSERROR_OK;
91}
92
93int32 amiga_warn_user_multi(const char *body, const char *opt1, const char *opt2, struct Window *win)
94{
95 int res = 0;
96
97 char *utf8text = ami_utf8_easy(body);
98 char *utf8gadget1 = ami_utf8_easy(messages_get(opt1));
99 char *utf8gadget2 = ami_utf8_easy(messages_get(opt2));
100 char *utf8gadgets = ASPrintf("%s|%s", utf8gadget1, utf8gadget2);
101 free(utf8gadget1);
102 free(utf8gadget2);
103
104#ifdef __amigaos4__
105 res = TimedDosRequesterTags(TDR_ImageType, TDRIMAGE_WARNING,
106 TDR_TitleString, messages_get("NetSurf"),
107 TDR_FormatString, utf8text,
108 TDR_GadgetString, utf8gadgets,
109 TDR_Window, win,
110 TAG_DONE);
111#else
112 struct EasyStruct easyreq = {
113 sizeof(struct EasyStruct),
114 0,
115 messages_get("NetSurf"),
116 utf8text,
117 utf8gadgets,
118 };
119
120 res = EasyRequest(win, &easyreq, NULL);
121#endif
122
123 if(utf8text) free(utf8text);
124 if(utf8gadgets) FreeVec(utf8gadgets);
125
126 return res;
127}
128
129/**
130 * Create a path from a nsurl using amiga file handling.
131 *
132 * @param[in] url The url to encode.
133 * @param[out] path_out A string containing the result path which should
134 * be freed by the caller.
135 * @return NSERROR_OK and the path is written to \a path or error code
136 * on faliure.
137 */
138static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out)
139{
140 lwc_string *urlpath;
141 size_t path_len;
142 char *path;
143 bool match;
144 lwc_string *scheme;
145 nserror res;
146 char *colon;
147 char *slash;
148
149 if ((url == NULL) || (path_out == NULL)) {
151 }
152
153 scheme = nsurl_get_component(url, NSURL_SCHEME);
154
155 if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
156 &match) != lwc_error_ok)
157 {
159 }
160 lwc_string_unref(scheme);
161 if (match == false) {
163 }
164
165 urlpath = nsurl_get_component(url, NSURL_PATH);
166 if (urlpath == NULL) {
168 }
169
170 res = url_unescape(lwc_string_data(urlpath) + 1, 0, &path_len, &path);
171 lwc_string_unref(urlpath);
172 if (res != NSERROR_OK) {
173 return res;
174 }
175
176 colon = strchr(path, ':');
177 if(colon == NULL) {
178 slash = strchr(path, '/');
179 if(slash) {
180 *slash = ':';
181 } else {
182 char *tmp_path = malloc(path_len + 2);
183 if(tmp_path == NULL) return NSERROR_NOMEM;
184
185 strncpy(tmp_path, path, path_len);
186 free(path);
187
188 path = tmp_path;
189 path[path_len] = ':';
190 path[path_len + 1] = '\0';
191 }
192 }
193
194 *path_out = path;
195
196 return NSERROR_OK;
197}
198
199/**
200 * Create a nsurl from a path using amiga file handling.
201 *
202 * Perform the necessary operations on a path to generate a nsurl.
203 *
204 * @param[in] path The path to convert.
205 * @param[out] url_out pointer to recive the nsurl, The returned url
206 * must be unreferenced by the caller.
207 * @return NSERROR_OK and the url is placed in \a url or error code on
208 * faliure.
209 */
210static nserror amiga_path_to_nsurl(const char *path, struct nsurl **url_out)
211{
212 char *colon = NULL;
213 char *r = NULL;
214 char newpath[1024 + strlen(path)];
215 BPTR lock = 0;
216 nserror ret;
217
218 if((lock = Lock(path, SHARED_LOCK))) {
219 DevNameFromLock(lock, newpath, sizeof newpath, DN_FULLPATH);
220 UnLock(lock);
221 }
222 else strlcpy(newpath, path, sizeof newpath);
223
224 r = malloc(strlen(newpath) + SLEN("file:///") + 1);
225 if (r == NULL) {
226 return NSERROR_NOMEM;
227 }
228
229 if((colon = strchr(newpath, ':'))) *colon = '/';
230
231 strcpy(r, "file:///");
232 strcat(r, newpath);
233
234 ret = nsurl_create(r, url_out);
235 free(r);
236
237 return ret;
238}
239
240/**
241 * returns a string with escape chars translated
242 * and string converted to local charset
243 * (based on remove_underscores from utils.c)
244 */
245
246char *translate_escape_chars(const char *s)
247{
248 size_t i, ii, len;
249 char *ret;
250 char *outs;
251 len = strlen(s);
252 ret = malloc(len + 1);
253 if (ret == NULL)
254 return NULL;
255 for (i = 0, ii = 0; i < len; i++) {
256 if (s[i] != '\\') {
257 ret[ii++] = s[i];
258 }
259 else if (s[i+1] == 'n') {
260 ret[ii++] = '\n';
261 i++;
262 }
263 }
264 ret[ii] = '\0';
265
266 outs = ami_utf8_easy(ret);
267 free(ret);
268 return outs;
269}
270
271/**
272 * Generate a posix path from one or more component elemnts.
273 *
274 * If a string is allocated it must be freed by the caller.
275 *
276 * @param[in,out] str pointer to string pointer if this is NULL enough
277 * storage will be allocated for the complete path.
278 * @param[in,out] size The size of the space available if \a str not
279 * NULL on input and if not NULL set to the total
280 * output length on output.
281 * @param[in] nelm The number of elements.
282 * @param[in] ap The elements of the path as string pointers.
283 * @return NSERROR_OK and the complete path is written to str
284 * or error code on faliure.
285 */
286static nserror amiga_vmkpath(char **str, size_t *size, size_t nelm, va_list ap)
287{
288 const char *elm[16];
289 size_t elm_len[16];
290 size_t elm_idx;
291 char *fname;
292 size_t fname_len = 0;
293
294 /* check the parameters are all sensible */
295 if ((nelm == 0) || (nelm > 16)) {
297 }
298 if ((*str != NULL) && (size == NULL)) {
299 /* if the caller is providing the buffer they must say
300 * how much space is available.
301 */
303 }
304
305 /* calculate how much storage we need for the complete path
306 * with all the elements.
307 */
308 for (elm_idx = 0; elm_idx < nelm; elm_idx++) {
309 elm[elm_idx] = va_arg(ap, const char *);
310 /* check the argument is not NULL */
311 if (elm[elm_idx] == NULL) {
313 }
314 elm_len[elm_idx] = strlen(elm[elm_idx]);
315 fname_len += elm_len[elm_idx];
316 }
317 fname_len += nelm; /* allow for separators and terminator */
318
319 /* ensure there is enough space */
320 fname = *str;
321 if (fname != NULL) {
322 if (fname_len > *size) {
323 return NSERROR_NOSPACE;
324 }
325 } else {
326 fname = malloc(fname_len);
327 if (fname == NULL) {
328 return NSERROR_NOMEM;
329 }
330 }
331
332 /* copy the first element complete */
333 memmove(fname, elm[0], elm_len[0]);
334 fname[elm_len[0]] = 0;
335
336 /* add the remaining elements */
337 for (elm_idx = 1; elm_idx < nelm; elm_idx++) {
338 if (!AddPart(fname, elm[elm_idx], fname_len)) {
339 break;
340 }
341 }
342
343 *str = fname;
344 if (size != NULL) {
345 *size = fname_len;
346 }
347
348 return NSERROR_OK;
349}
350
351/**
352 * Get the basename of a file using posix path handling.
353 *
354 * This gets the last element of a path and returns it.
355 *
356 * @param[in] path The path to extract the name from.
357 * @param[in,out] str Pointer to string pointer if this is NULL enough
358 * storage will be allocated for the path element.
359 * @param[in,out] size The size of the space available if \a
360 * str not NULL on input and set to the total
361 * output length on output.
362 * @return NSERROR_OK and the complete path is written to str
363 * or error code on faliure.
364 */
365static nserror amiga_basename(const char *path, char **str, size_t *size)
366{
367 const char *leafname;
368 char *fname;
369
370 if (path == NULL) {
372 }
373
374 leafname = FilePart(path);
375 if (leafname == NULL) {
377 }
378
379 fname = strdup(leafname);
380 if (fname == NULL) {
381 return NSERROR_NOMEM;
382 }
383
384 *str = fname;
385 if (size != NULL) {
386 *size = strlen(fname);
387 }
388 return NSERROR_OK;
389}
390
391/**
392 * Ensure that all directory elements needed to store a filename exist.
393 *
394 * @param fname The filename to ensure the path to exists.
395 * @return NSERROR_OK on success or error code on failure.
396 */
397static nserror amiga_mkdir_all(const char *fname)
398{
399 char *dname;
400 char *sep;
401 struct stat sb;
402
403 dname = strdup(fname);
404
405 sep = strrchr(dname, '/');
406 if (sep == NULL) {
407 /* no directory separator path is just filename so its ok */
408 free(dname);
409 return NSERROR_OK;
410 }
411
412 *sep = 0; /* null terminate directory path */
413
414 if (stat(dname, &sb) == 0) {
415 free(dname);
416 if (S_ISDIR(sb.st_mode)) {
417 /* path to file exists and is a directory */
418 return NSERROR_OK;
419 }
421 }
422 *sep = '/'; /* restore separator */
423
424 sep = dname;
425 while (*sep == '/') {
426 sep++;
427 }
428 while ((sep = strchr(sep, '/')) != NULL) {
429 *sep = 0;
430 if (stat(dname, &sb) != 0) {
431 if (nsmkdir(dname, S_IRWXU) != 0) {
432 /* could not create path element */
433 free(dname);
434 return NSERROR_NOT_FOUND;
435 }
436 } else {
437 if (! S_ISDIR(sb.st_mode)) {
438 /* path element not a directory */
439 free(dname);
441 }
442 }
443 *sep = '/'; /* restore separator */
444 /* skip directory separators */
445 while (*sep == '/') {
446 sep++;
447 }
448 }
449
450 free(dname);
451 return NSERROR_OK;
452}
453
454/* amiga file handling operations */
455static struct gui_file_table file_table = {
457 .basename = amiga_basename,
458 .nsurl_to_path = amiga_nsurl_to_path,
459 .path_to_nsurl = amiga_path_to_nsurl,
460 .mkdir_all = amiga_mkdir_all,
461};
462
struct Window * ami_gui_get_window(struct gui_window *gw)
Get window from gui_window.
Definition: gui.c:576
struct gui_window * ami_gui_get_active_gw(void)
Get a pointer to the gui_window which NetSurf considers to be the current/active one.
Definition: gui.c:398
static struct gui_window * cur_gw
Definition: gui.c:328
void ami_misc_fatal_error(const char *message)
Definition: misc.c:73
static LONG ami_misc_req(const char *message, uint32 type)
Definition: misc.c:45
static nserror amiga_mkdir_all(const char *fname)
Ensure that all directory elements needed to store a filename exist.
Definition: misc.c:397
int32 amiga_warn_user_multi(const char *body, const char *opt1, const char *opt2, struct Window *win)
Definition: misc.c:93
static nserror amiga_vmkpath(char **str, size_t *size, size_t nelm, va_list ap)
Generate a posix path from one or more component elemnts.
Definition: misc.c:286
nserror amiga_warn_user(const char *warning, const char *detail)
Warn the user of an event.
Definition: misc.c:79
static nserror amiga_path_to_nsurl(const char *path, struct nsurl **url_out)
Create a nsurl from a path using amiga file handling.
Definition: misc.c:210
static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out)
Create a path from a nsurl using amiga file handling.
Definition: misc.c:138
static nserror amiga_basename(const char *path, char **str, size_t *size)
Get the basename of a file using posix path handling.
Definition: misc.c:365
char * translate_escape_chars(const char *s)
returns a string with escape chars translated and string converted to local charset (based on remove_...
Definition: misc.c:246
static struct gui_file_table file_table
Definition: misc.c:455
struct gui_file_table * amiga_file_table
Definition: misc.c:463
Useful interned string pointers (interface).
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOSPACE
Insufficient space.
Definition: errors.h:59
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_NOT_DIRECTORY
Missing directory.
Definition: errors.h:35
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
char * ami_utf8_easy(const char *string)
Definition: utf8.c:109
Interface to platform-specific graphical user interface window operations.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
NetSurf URL handling (interface).
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
lwc_string * nsurl_get_component(const nsurl *url, nsurl_component part)
Get part of a URL as a lwc_string, from a NetSurf URL object.
@ NSURL_SCHEME
Definition: nsurl.h:45
@ NSURL_PATH
Definition: nsurl.h:52
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
char * ASPrintf(const char *fmt,...)
Definition: os3support.c:139
#define DN_FULLPATH
Definition: os3support.h:123
@ TDRIMAGE_ERROR
Definition: os3support.h:232
@ TDRIMAGE_WARNING
Definition: os3support.h:233
#define DevNameFromLock(A, B, C, D)
Definition: os3support.h:162
int32_t int32
Definition: os3support.h:183
uint32_t uint32
Definition: os3support.h:184
Interface to utility string handling.
/brief function table for file and filename operations.
Definition: file.h:50
nserror(* mkpath)(char **str, size_t *size, size_t nemb, va_list ap)
Generate a path from one or more component elemnts.
Definition: file.h:68
first entry in window list
Definition: gui.c:296
nserror url_unescape(const char *str, size_t length, size_t *length_out, char **result_out)
Convert an escaped string to plain.
Definition: url.c:67
Interface to URL parsing and joining operations.
Default operations table for files.
Interface to a number of general purpose functionality.
#define nsmkdir(dir, mode)
POSIX mkdir function.
Definition: utils.h:60
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:84
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821