Edinburgh Speech Tools  2.1-release
url.c
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Copyright (c) 1997-98 Richard Tobin, Language Technology Group, HCRC, */
4 /* University of Edinburgh. */
5 /* */
6 /* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, */
7 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
8 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
9 /* IN NO EVENT SHALL THE AUTHOR OR THE UNIVERSITY OF EDINBURGH BE LIABLE */
10 /* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF */
11 /* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION */
12 /* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
13 /* */
14 /*************************************************************************/
15 #define _POSIX_SOURCE
16 #ifdef FOR_LT
17 
18 #include "lt-defs.h"
19 #include "lt-memory.h"
20 #include "lt-errmsg.h"
21 #include "lt-comment.h"
22 #include "lt-safe.h"
23 #include "nsl-err.h"
24 
25 #define Strerror() strErr()
26 #define Malloc salloc
27 #define Realloc srealloc
28 #define Free sfree
29 #define fopen stdsfopen
30 
31 #else
32 
33 #include "system.h"
34 
35 #define LT_ERROR(err, format) fprintf(stderr, format)
36 #define LT_ERROR1(err, format, arg) fprintf(stderr, format, arg)
37 #define LT_ERROR2(err, format, arg1, arg2) fprintf(stderr, format, arg1, arg2)
38 #define LT_ERROR3(err, format, arg1, arg2, arg3) fprintf(stderr, format, arg1, arg2, arg3)
39 #define WARN(err, format) fprintf(stderr, format)
40 #define WARN1(err, format, arg) fprintf(stderr, format, arg)
41 
42 #define Strerror() strerror(errno)
43 
44 #ifdef MAXPATHLEN
45 #define CWDBS MAXPATHLEN+1
46 #else
47 #define CWDBS 1025
48 #endif
49 
50 #define GETWD(buf) getcwd(buf,CWDBS)
51 
52 #endif /* FOR_LT */
53 
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <stdlib.h>
57 #include <assert.h>
58 #include <errno.h>
59 #include <string.h> /* that's where strerror is. really. */
60 #include <sys/types.h>
61 
62 #ifdef WIN32
63 #include <direct.h>
64 #endif
65 
66 #ifdef SOCKETS_IMPLEMENTED
67 
68 #ifdef WIN32
69 #undef boolean
70 #include <winsock.h>
71 #include <fcntl.h>
72 #else
73 #include <unistd.h>
74 #include <netdb.h>
75 #include <sys/socket.h>
76 #include <netinet/in.h>
77 #endif
78 
79 #endif
80 
81 #include "string16.h"
82 #include "stdio16.h"
83 #include "url.h"
84 
85 #ifdef HAVE_LIBZ
86 #include "zlib.h"
87 #ifdef macintosh
88 #include <fcntl.h>
89 #include <unix.h>
90 #endif
91 #endif
92 
93 static FILE16 *http_open(const char *url,
94  const char *host, int port, const char *path,
95  const char *type);
96 static FILE16 *file_open(const char *url,
97  const char *host, int port, const char *path,
98  const char *type);
99 
100 static int parse_url(const char *url,
101  char **scheme, char **host, int *port, char **path);
102 
103 /* Mapping of scheme names to opening functions */
104 
105 struct {
106  char *scheme;
107  FILE16 *(*open)(const char *, const char *, int, const char *, const char *);
108 } schemes[] = {
109  {(char *)"http", http_open},
110  {(char *)"file", file_open},
111 };
112 #define NSCHEME (sizeof(schemes) / sizeof(schemes[0]))
113 
114 /* Construct a default base URL, essentially file:`pwd`/ */
115 
116 char *default_base_url(void)
117 {
118  char buf[CWDBS];
119  char *url;
120 
121  if(!GETWD(buf))
122  {
123  WARN(LEFILE, "Warning: can't get current directory for default base url\n");
124  return strdup8("file:/");
125  }
126 
127 
128 #ifdef WIN32
129 
130  /* DOS: translate C:\a\b to file:/C:/a/b/ */
131  /* XXX should we escape anything? */
132  {
133  char *p;
134  for(p=buf; *p; p++)
135  if(*p == '\\')
136  *p = '/';
137  }
138  url = Malloc(6 + strlen(buf) + 2);
139  if (url == NULL) {
140  return NULL;
141  }
142  sprintf(url, "file:/%s/", buf);
143 
144 #else
145 #ifdef mac_filenames
146 
147  /* Mac: translate a:b to file:/a/b/ */
148  /* XXX should escape spaces and slashes, at least */
149  {
150  char *p;
151  for(p=buf; *p; p++)
152  if(*p == ':')
153  *p = '/';
154  /* Mac getcwd (always?) has a trailing separator, which we here bash */
155  if(*--p == '/')
156  *p = 0;
157  }
158  url = Malloc(6 + strlen(buf) + 2);
159  if (url == NULL) {
160  return NULL;
161  }
162  sprintf(url, "file:/%s/", buf);
163 
164 #else
165 
166  /* Unix: translate /a/b to file:/a/b/ */
167 
168  url = Malloc(5 + strlen(buf) + 2);
169  if (url == NULL) {
170  return NULL;
171  }
172  sprintf(url, "file:%s/", buf);
173 
174 #endif
175 #endif
176 
177  return url;
178 }
179 
180 /*
181  * Merge a URL with a base URL if necessary.
182  * The merged URL is returned.
183  * The parts of the URL are returned in scheme, host, port and path
184  * if these are non-null.
185  * Caller should free the results.
186  */
187 
188 char *url_merge(const char *url, const char *base,
189  char **_scheme, char **_host, int *_port, char **_path)
190 {
191  char *merged_scheme, *merged_host, *merged_path, *merged_url;
192  char *scheme=0, *host=0, *path=0;
193  char *base_scheme=0, *base_host=0, *base_path=0;
194  char *default_base=0;
195  int port, base_port, merged_port, i, j;
196  char *p;
197 
198  /* First see if we have an absolute URL */
199 
200  if (parse_url(url, &scheme, &host, &port, &path) < 0) {
201  goto bad;
202  }
203  if(scheme && (host || *path == '/'))
204  {
205  merged_scheme = scheme;
206  merged_host = host;
207  merged_port = port;
208  merged_path = path;
209  merged_url = strdup8(url);
210  goto ok;
211  }
212 
213  /* Relative URL, so we need the base URL */
214 
215  if(!base)
216  base = default_base = default_base_url();
217 
218  if (parse_url(base, &base_scheme, &base_host, &base_port, &base_path) < 0) {
219  goto bad;
220  }
221  if(base_scheme && (base_host || *base_path == '/'))
222  ;
223  else
224  {
225  LT_ERROR1(LEFILE, "Error: bad base URL <%s>\n", base);
226  goto bad;
227  }
228 
229  /* Determine merged path */
230 
231  if(path[0] == '/')
232  {
233  /* not relative, use as-is */
234  merged_path = path;
235  path = 0;
236  }
237  else
238  {
239  /* relative, append to base path */
240 
241  merged_path = Malloc(strlen(base_path) + strlen(path) + 1);
242  strcpy(merged_path, base_path);
243 
244  /* strip last component of base */
245 
246  for(i=strlen(merged_path)-1; i>=0 && merged_path[i] != '/'; i--)
247  merged_path[i] = '\0';
248 
249  /* append relative path */
250 
251  strcat(merged_path, path);
252 
253  /* Remove . and .. components from path */
254 
255  p = merged_path;
256  for(i=0; p[i]; )
257  {
258  assert(p[i] == '/');
259 
260  /* find next segment */
261 
262  for(j=i+1; p[j] && p[j] != '/'; j++)
263  ;
264 
265  /* Do we have "." ? */
266 
267  if(j - i == 2 && p[i+1] == '.')
268  {
269  strcpy(&p[i+1], p[j] ? &p[j+1] : &p[j]);
270  continue;
271  }
272 
273  /* Do we have "<segment>/.." with <segment> != ".." ? */
274 
275  /* (We know we're not looking at "./" so we don't have to
276  * worry about "./..")
277  */
278 
279  if(p[j] == '/' && p[j+1] == '.' && p[j+2] == '.' &&
280  (p[j+3] == '/' || p[j+3] == '\0') &&
281  (j - i != 3 || p[i+1] != '.' || p[i+2] != '.'))
282  {
283  strcpy(&p[i+1], p[j+3] ? &p[j+4] : &p[j+3]);
284  i = 0; /* start again from beginning */
285  continue;
286  }
287 
288  /* move to next segment */
289 
290  i = j;
291  }
292  }
293 
294  /* Check for deviant relative URLs like file:foo */
295 
296  if(scheme && !host && *path != '/')
297  {
298  if(strcmp(scheme, base_scheme) == 0)
299  {
300  WARN1(LEFILE,
301  "Warning: relative URL <%s> contains scheme, contrary to RFC 1808\n",
302  url);
303  }
304  else
305  {
306  LT_ERROR2(LEFILE,
307  "Error: relative URL <%s> has scheme different from base <%s>\n",
308  url, base);
309  Free(merged_path);
310  goto bad;
311  }
312  }
313 
314  /* Return the parts and the whole thing */
315 
316  merged_scheme = base_scheme; if(scheme) Free(scheme);
317 
318  if(host)
319  {
320  merged_host = host; Free(base_host);
321  merged_port = port;
322  }
323  else
324  {
325  merged_host = base_host;
326  merged_port = base_port;
327  }
328 
329  Free(path); Free(base_path);
330 
331  merged_url = Malloc(strlen(merged_scheme) + 1 +
332  (merged_host ? 2 + strlen(merged_host) + 10 : 0) +
333  strlen(merged_path) + 1);
334  if (merged_url == NULL) {
335  goto bad;
336  }
337  if(merged_host)
338  {
339  if(merged_port == -1)
340  sprintf(merged_url, "%s://%s%s",
341  merged_scheme, merged_host, merged_path);
342  else
343  sprintf(merged_url, "%s://%s:%d%s",
344  merged_scheme, merged_host, merged_port, merged_path);
345  }
346  else
347  sprintf(merged_url, "%s:%s", merged_scheme, merged_path);
348 
349 ok:
350  Free(default_base);
351  if(_scheme) *_scheme = merged_scheme; else Free(merged_scheme);
352  if(_host) *_host = merged_host; else Free(merged_host);
353  if(_port) *_port = merged_port;
354  if(_path) *_path = merged_path; else Free(merged_path);
355 
356  return merged_url;
357 
358 bad:
359  Free(default_base);
360  Free(scheme);
361  Free(host);
362  Free(path);
363  Free(base_scheme);
364  Free(base_host);
365  Free(base_path);
366 
367  return NULL;
368 }
369 
370 /*
371  * Open a stream to a URL.
372  * url may be a relative URL, in which case it is merged with base,
373  * which is typically the URL of the containing document. If base
374  * is null, file:`pwd`/ is used, which is the right thing to do for
375  * filenames. If base is "", there is no base URL and relative
376  * URLs will fail.
377  * If merged_url is non-null the resulting URL is stored in it.
378  * If type begins "r", the URL is opened for reading, if "w" for
379  * writing. Writing is only supported for file URLs.
380  * If the type begins "rl", the data will be copied to a temporary
381  * file so that seeking is possible (NOT YET IMPLEMENTED).
382  * Returns a FILE16 for success, NULL for failure.
383  */
384 
385 FILE16 *url_open(const char *url, const char *base, const char *type,
386  char **merged_url)
387 {
388  char *scheme =NULL, *host, *path, *m_url;
389  int port;
390  unsigned int i;
391  FILE16 *f;
392 #ifdef HAVE_LIBZ
393  int len, gzipped = 0;
394 #endif
395 
396  /* Determine the merged URL */
397 
398  if(!(m_url = url_merge(url, base, &scheme, &host, &port, &path))) {
399  Free(path);
400  Free(scheme);
401  return 0;
402  }
403 
404 #ifdef HAVE_LIBZ
405  len = strlen(m_url);
406  if(len > 3 && strcmp8(m_url+len-3, ".gz") == 0)
407  gzipped = 1;
408 #endif
409 
410  /*
411  printf("<%s> <%s> <%d> <%s>\n", scheme, host ? host : "", port, path);
412  printf("%s\n", m_url);
413  */
414 
415  /* Pass to the appropriate opening function */
416 
417  for(i=0; i<NSCHEME; i++)
418  if(strcmp(scheme, schemes[i].scheme) == 0)
419  {
420  f = schemes[i].open(m_url, host, port, path, type);
421 
422  Free(scheme);
423  if(host)
424  Free(host);
425  Free(path);
426 
427  if(!f)
428  return f;
429 
430 #ifdef HAVE_LIBZ
431  if(gzipped)
432  {
433  /* We have a gzip-compressed file which we hand to gzopen
434  * for further processing.
435  */
436  gzFile gfile;
437  FILE *file = GetFILE(f);
438 
439  if(!f)
440  {
441  LT_ERROR1(LEFILE,
442  "Can't attach gzip processor to URL \"%s\"\n",
443  m_url);
444  Free(m_url);
445  return 0;
446  }
447 #ifdef macintosh
448  gfile =gzdopen(dup(fileno(file)), *type == 'r' ? "rb" : "wb");
449 #else
450  gfile = gzdopen(dup(fileno(file)), type);
451 #endif
452  Fclose(f);
453  f = MakeFILE16FromGzip(gfile, type);
454  }
455 #endif
456  if(f && merged_url)
457  *merged_url = m_url;
458  else
459  Free(m_url);
460 
461  return f;
462  }
463 
464  /* Not implemented */
465 
466  LT_ERROR1(LEFILE, "Error: scheme \"%s\" not implemented\n", scheme);
467 
468  Free(scheme);
469  if(host)
470  Free(host);
471  Free(path);
472  Free(m_url);
473 
474  return 0;
475 }
476 
477 /* Open an http URL */
478 
479 static FILE16 *http_open(const char *url,
480  const char *host, int port, const char *path,
481  const char *type)
482 {
483 #ifndef SOCKETS_IMPLEMENTED
484  LT_ERROR(NEUNSUP,
485  "http: URLs are not yet implemented on this platform\n");
486  return 0;
487 #else
488  FILE16 *f16;
489  struct sockaddr_in addr;
490  struct hostent *hostent;
491  int s, server_major, server_minor, status, count, c;
492  char reason[81];
493 #ifndef WIN32
494  FILE *fin,*fout;
495 #else
496  static int inited=0;
497  int i;
498  static char buf[1024];
499  if (!inited)
500  {
501  WORD version = MAKEWORD(1, 1);
502  WSADATA wsaData;
503  int err = WSAStartup(version, &wsaData);
504  if (err)
505  {
506  LT_ERROR(LEFILE, "Error: can't init HTTP interface\n");
507  return 0;
508  }
509  else if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
510  {
511  LT_ERROR(LEFILE, "Error: wrong version of WINSOCK\n");
512  WSACleanup();
513  return 0;
514  }
515  inited = 1;
516  }
517 #endif
518 
519  if(*type != 'r')
520  {
521  LT_ERROR1(LEFILE, "Error: can't open http URL \"%s\" for writing\n",
522  url);
523  return 0;
524  }
525 
526  if(!host)
527  {
528  LT_ERROR1(LEFILE, "Error: no host part in http URL \"%s\"\n", url);
529  return 0;
530  }
531 
532  /* Create the socket */
533 
534  s = socket(PF_INET, SOCK_STREAM, 0);
535 #ifdef WIN32
536  if (s == INVALID_SOCKET) {
537  LT_ERROR1(LEFILE, "Error: system call socket failed: %d\n",
538  WSAGetLastError());
539  };
540 #else
541  if(s == -1) {
542  LT_ERROR1(LEFILE, "Error: system call socket failed: %s\n",
543  Strerror());
544  return 0;
545  };
546 #endif
547 
548  /* Find the server address */
549 
550  hostent = gethostbyname(host);
551  if(!hostent)
552  {
553  LT_ERROR1(LEFILE,
554  "Error: can't find address for host in http URL \"%s\"\n",
555  url);
556  close(s);
557  return 0;
558  }
559 
560  memset(&addr, 0, sizeof(addr));
561  addr.sin_family = AF_INET;
562  /* If we were really enthusiastic, we would try all the host's addresses */
563  memcpy(&addr.sin_addr, hostent->h_addr_list[0], hostent->h_length);
564  addr.sin_port = htons((uint16_t)(port == -1 ? 80 : port));
565 
566  /* Connect */
567 
568  if(connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
569  {
570  LT_ERROR1(LEFILE, "Error: system call connect failed: %s\n",
571  Strerror());
572  close(s);
573  return 0;
574  }
575 
576 #ifndef WIN32
577 #ifdef macintosh
578  fin = fdopen(s, "rb");
579  setvbuf(fin, 0, _IONBF, 0);
580  fout = fdopen(dup(s), "wb");
581 #else
582  fin = fdopen(s, "r");
583  setvbuf(fin, 0, _IONBF, 0);
584  int newfd = dup(s);
585  if (newfd < 0) {
586  LT_ERROR(LEFILE,
587  "Error: http_open: Can't copy file descriptor\n");
588  close(s);
589  fclose(fin);
590  return 0;
591  }
592  fout = fdopen(newfd, "w");
593 #endif
594 #endif
595 
596  /* Send the request */
597 
598  /*
599  * Apparently on the Macintosh, \n might not be ASCII LF, so we'll
600  * use numerics to be sure.
601  */
602 
603 #ifdef WIN32
604  sprintf(buf, "GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
605  path);
606  if (send(s,buf,strlen8(buf),0)==SOCKET_ERROR) {
607  LT_ERROR1(LEFILE, "Error: system call socket failed: %d\n",
608  WSAGetLastError());
609  /* XXX close the socket? */
610  return 0;
611  };
612 #else
613  fprintf(fout, "GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
614  path);
615 
616  /* We used to test for errors after doing fclose, but this seemed
617  to produce spurious errors under Linux (RedHat 4.2), so now we
618  do fflush and test after that. */
619 
620  fflush(fout);
621  if(ferror(fout))
622  {
623  LT_ERROR1(LEWRTF, "Error: write to socket failed: %s\n",Strerror());
624  fclose(fout);
625  fclose(fin);
626  return 0;
627  }
628  fclose(fout);
629 #endif
630 
631  /* Read the status line */
632 #ifdef WIN32
633  for(i=0; i<sizeof(buf)-1; i++)
634  {
635  if(recv(s, &buf[i], 1, 0) != 1)
636  LT_ERROR1(LEFILE,
637  "Error: recv error from server for URL \"%s\"\n",
638  url);
639  if(buf[i] == '\n')
640  break;
641  }
642  count=sscanf(buf, "HTTP/%d.%d %d %80[^\012]",
643  &server_major, &server_minor, &status, reason);
644 #else
645  count=fscanf(fin, "HTTP/%d.%d %d %80[^\012]",
646  &server_major, &server_minor, &status, reason);
647 #endif
648 
649  if(count != 4)
650  {
651  LT_ERROR3(LEFILE,
652  "Error: bad header from server for URL \"%s\"\n%d %s\n",
653  url, count, Strerror());
654 #ifndef WIN32
655  fclose(fin);
656 #endif
657  return 0;
658  }
659 
660  if(status != 200)
661  {
662  /* We should handle 301 (redirection) but we don't */
663  LT_ERROR3(LEFILE, "Error: can't retrieve \"%s\": %d %s\n",
664  url, status, reason);
665 #ifndef WIN32
666  fclose(fin);
667 #endif
668  return 0;
669  }
670 
671  /* Skip other headers */
672 
673  count = 0;
674 #ifdef WIN32
675  while(recv(s, buf, 1, 0) == 1 && (c = buf[0], 1) || (c = EOF, 0))
676 #else
677  while((c = getc(fin)) != EOF)
678 #endif
679  {
680  if(c == '\012')
681  count++;
682  else if(c != '\015')
683  count = 0;
684  if(count == 2)
685  break;
686  }
687 
688  if(c == EOF)
689  {
690  LT_ERROR1(LEFILE, "Error: EOF in headers retrieving \"%s\"\n", url);
691 #ifndef WIN32
692  fclose(fin);
693 #endif
694  return 0;
695  }
696 
697 #ifdef WIN32
698  f16 = MakeFILE16FromWinsock(s, type);
699 #else
700  f16 = MakeFILE16FromFILE(fin, type);
701 #endif
702 
703  SetCloseUnderlying(f16, 1);
704  return f16;
705 #endif /* SOCKETS_IMPLEMENTED */
706 }
707 
708 /* Open a file URL (easy, at least on unix) */
709 
710 static FILE16 *file_open(const char *url,
711  const char *host, int port, const char *path,
712  const char *type)
713 {
714  FILE *f;
715  FILE16 *f16;
716  char *file;
717  (void) port;
718  if(host && host[0])
719  WARN1(LEFILE, "Warning: ignoring host part in file URL \"%s\"\n", url);
720 
721 #ifdef WIN32
722 
723  /* DOS: translate /C:/a/b.c to C:\a\b.c */
724 
725  if(path[0] == '/' && path[1] && path[2] == ':')
726  path++;
727 
728  file = strdup8(path);
729  {
730  char *p;
731  for(p=file; *p; p++)
732  if(*p == '/')
733  *p = '\\';
734  }
735 
736 #else
737 #ifdef mac_filenames
738 
739  /* Mac: translate /a/b.c to a:b.c */
740 
741  if(*path == '/')
742  path++;
743 
744  file = strdup8(path);
745  {
746  char *p;
747  for(p=file; *p; p++)
748  if(*p == '/')
749  *p = ':';
750  }
751 #else
752 
753  /* Unix: a path is a path is a path! */
754 
755  file = strdup8(path);
756 
757 #endif
758 #endif
759 
760  /* XXX should undo any escapes */
761 
762  f = fopen(file, type);
763  if(!f)
764  {
765  perror(file);
766  Free(file);
767  return 0;
768  }
769 
770  Free(file);
771 
772  f16 = MakeFILE16FromFILE(f, type);
773  SetCloseUnderlying(f16, 1);
774 
775  return f16;
776 }
777 
778 static int parse_url(const char *url,
779  char **scheme, char **host, int *port, char **path)
780 {
781  char *p, *q;
782  int warned = 0;
783 
784  *scheme = *host = *path = 0;
785  *port = -1;
786 
787  /* Does it start with a scheme? */
788 
789  for(p = (char *)url; *p; p++)
790  if(*p == ':' || *p == '/')
791  break;
792 
793  if(p > url && *p == ':')
794  {
795  *scheme = Malloc(p - url + 1);
796  if (*scheme == NULL) {
797  return -1;
798  }
799  strncpy(*scheme, url, p - url);
800  (*scheme)[p - url] = '\0';
801  url = p+1;
802  }
803 
804  /* Does it have a net_loc? */
805 
806  if(url[0] == '/' && url[1] == '/')
807  {
808  url += 2;
809 
810  for(p = (char *)url; *p; p++)
811  if(*p == '/')
812  break;
813 
814  /* Does it have a port number? */
815 
816  for(q = p-1; q >= url; q--)
817  if(!isdigit((int)*q))
818  break;
819 
820  if(q < p-1 && *q == ':')
821  *port = atoi(q+1);
822  else
823  q = p;
824 
825  *host = Malloc(q - url + 1);
826  if (*host == NULL) {
827  return -1;
828  }
829  strncpy(*host, url, q - url);
830  (*host)[q - url] = '\0';
831  url = p;
832  }
833 
834  /* The rest is the path */
835 
836  if(*url)
837  *path = strdup8(url);
838  else
839  *path = strdup8("/");
840 
841  /* Windoze users have a tendency to use backslashes instead of slashes */
842 
843  for(p=*path; *p; p++)
844  if(*p == '\\')
845  {
846  if(!warned)
847  {
848  WARN1(LEFILE, "Warning: illegal backslashes in URL path \"%s\""
849  "replaced by slashes\n", url);
850  warned = 1;
851  }
852 
853  *p = '/';
854  }
855  return 0;
856 }
857 
#define strlen8(s)
Definition: string16.h:51
#define NSCHEME
Definition: url.c:112
#define Strerror()
Definition: url.c:42
char * default_base_url(void)
Definition: url.c:116
#define WARN1(err, format, arg)
Definition: url.c:40
#define LT_ERROR3(err, format, arg1, arg2, arg3)
Definition: url.c:38
#define LT_ERROR1(err, format, arg)
Definition: url.c:36
STD_API FILE16 * MakeFILE16FromFILE(FILE *f, const char *type)
Definition: stdio16.c:670
#define GETWD(buf)
Definition: url.c:50
STD_API void SetCloseUnderlying(FILE16 *file, int cu)
Definition: stdio16.c:347
#define WARN(err, format)
Definition: url.c:39
char * url_merge(const char *url, const char *base, char **_scheme, char **_host, int *_port, char **_path)
Definition: url.c:188
FILE16 * url_open(const char *url, const char *base, const char *type, char **merged_url)
Definition: url.c:385
#define strcmp8(s1, s2)
Definition: string16.h:52
struct @20 schemes[]
void Free(void *mem)
Definition: system.c:35
char * scheme
Definition: url.c:106
void err(const char *message, LISP x) EST_NORETURN
Definition: slib.cc:608
#define LT_ERROR2(err, format, arg1, arg2)
Definition: url.c:37
NULL
Definition: EST_WFST.cc:55
f
Definition: EST_item_aux.cc:48
STD_API FILE * GetFILE(FILE16 *file)
Definition: stdio16.c:339
getString int
Definition: EST_item_aux.cc:50
#define CWDBS
Definition: url.c:47
#define LT_ERROR(err, format)
Definition: url.c:35
STD_API int Fclose(FILE16 *file)
Definition: stdio16.c:319
#define WORD
Definition: rateconv.cc:172
STD_API char8 * strdup8(const char8 *s)
Definition: string16.c:77
void * Malloc(int bytes)
Definition: system.c:19
int parse_url(const EST_String &url, EST_String &protocol, EST_String &host, EST_String &port, EST_String &path)
Definition: io.cc:80