746:a569148841ff | 747:efbd59642577 |
---|---|
36 #include <time.h> | 36 #include <time.h> |
37 #include <sys/types.h> | 37 #include <sys/types.h> |
38 #ifndef _WIN32 | 38 #ifndef _WIN32 |
39 #include <sys/wait.h> | 39 #include <sys/wait.h> |
40 #endif | 40 #endif |
41 #include <ucx/string.h> | 41 #include <cx/string.h> |
42 #include <ucx/utils.h> | 42 #include <cx/utils.h> |
43 #include <cx/printf.h> | |
44 #include <cx/hash_map.h> | |
45 #include <cx/linked_list.h> | |
43 #include <dirent.h> | 46 #include <dirent.h> |
44 | 47 |
45 #include <libidav/utils.h> | 48 #include <libidav/utils.h> |
46 #include <libidav/crypto.h> | 49 #include <libidav/crypto.h> |
47 #include <libidav/session.h> | 50 #include <libidav/session.h> |
158 if(!strcasecmp(cmd, "list") || !strcasecmp(cmd, "ls")) { | 161 if(!strcasecmp(cmd, "list") || !strcasecmp(cmd, "ls")) { |
159 ret = cmd_list(args); | 162 ret = cmd_list(args); |
160 } else if(!strcasecmp(cmd, "get")) { | 163 } else if(!strcasecmp(cmd, "get")) { |
161 ret = cmd_get(args, FALSE); | 164 ret = cmd_get(args, FALSE); |
162 } else if(!strcasecmp(cmd, "cat")) { | 165 } else if(!strcasecmp(cmd, "cat")) { |
163 ucx_map_cstr_put(args->options, "output", "-"); | 166 cxMapPut(args->options, cx_hash_key_str("output"), "-"); |
164 ret = cmd_get(args, FALSE); | 167 ret = cmd_get(args, FALSE); |
165 } else if(!strcasecmp(cmd, "edit")) { | 168 } else if(!strcasecmp(cmd, "edit")) { |
166 ret = cmd_edit(args); | 169 ret = cmd_edit(args); |
167 } else if(!strcasecmp(cmd, "put")) { | 170 } else if(!strcasecmp(cmd, "put")) { |
168 ret = cmd_put(args, FALSE); | 171 ret = cmd_put(args, FALSE); |
272 "date [url]", | 275 "date [url]", |
273 NULL | 276 NULL |
274 }; | 277 }; |
275 | 278 |
276 char* find_usage_str(const char *cmd) { | 279 char* find_usage_str(const char *cmd) { |
277 scstr_t c = scstr(cmd); | 280 cxstring c = cx_str(cmd); |
278 for(int i=0;;i++) { | 281 for(int i=0;;i++) { |
279 char *str = cmdusageinfo[i]; | 282 char *str = cmdusageinfo[i]; |
280 if(!str) { | 283 if(!str) { |
281 break; | 284 break; |
282 } | 285 } |
283 scstr_t u = scstr(str); | 286 cxstring u = cx_str(str); |
284 if(sstrprefix(u, c)) { | 287 if(cx_strprefix(u, c)) { |
285 return str; | 288 return str; |
286 } | 289 } |
287 } | 290 } |
288 return NULL; | 291 return NULL; |
289 } | 292 } |
589 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few":"many"); | 592 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few":"many"); |
590 fprintf(stderr, "Usage: dav %s\n", find_usage_str("get")); | 593 fprintf(stderr, "Usage: dav %s\n", find_usage_str("get")); |
591 return -1; | 594 return -1; |
592 } | 595 } |
593 if(export) { | 596 if(export) { |
594 ucx_map_cstr_put(a->options, "recursive", ""); | 597 cxMapPut(a->options, cx_hash_key_str("recursive"), ""); |
595 } | 598 } |
596 | 599 |
597 char *url = a->argv[0]; | 600 char *url = a->argv[0]; |
598 char *path = NULL; | 601 char *path = NULL; |
599 Repository *repo = url2repo(url, &path); | 602 Repository *repo = url2repo(url, &path); |
692 "if the requested resource is a collection.\n"); | 695 "if the requested resource is a collection.\n"); |
693 return -1; | 696 return -1; |
694 } | 697 } |
695 | 698 |
696 // get list of resources | 699 // get list of resources |
697 UcxList *reslist = NULL; | 700 CxList *reslist = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
701 reslist->simple_destructor = (cx_destructor_func)free_getres; | |
698 uint64_t totalsize = 0; | 702 uint64_t totalsize = 0; |
699 uint64_t rescount = 0; | 703 uint64_t rescount = 0; |
700 | 704 |
701 GetResource *getres = malloc(sizeof(GetResource)); | 705 GetResource *getres = malloc(sizeof(GetResource)); |
702 getres->res = res; | 706 getres->res = res; |
703 getres->path = strdup(basepath); | 707 getres->path = strdup(basepath); |
704 | 708 |
705 char *structure = cmd_getoption(a, "structure"); | 709 char *structure = cmd_getoption(a, "structure"); |
706 | 710 |
707 // iterate over resource tree | 711 // iterate over resource tree |
708 UcxList *stack = ucx_list_prepend(NULL, getres); | 712 CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
709 while(stack) { | 713 cxListInsert(stack, 0, getres); |
710 GetResource *g = stack->data; | 714 while(stack->size > 0) { |
711 stack = ucx_list_remove(stack, stack); | 715 GetResource *g = cxListAt(stack, 0); |
716 cxListRemove(stack, 0); | |
712 | 717 |
713 if(g->res->iscollection) { | 718 if(g->res->iscollection) { |
714 DavResource *child = g->res->children; | 719 DavResource *child = g->res->children; |
715 while(child) { | 720 while(child) { |
716 // add resource to stack | 721 // add resource to stack |
718 GetResource *newres = malloc(sizeof(GetResource)); | 723 GetResource *newres = malloc(sizeof(GetResource)); |
719 newres->res = child; | 724 newres->res = child; |
720 newres->path = pathlen > 0 ? | 725 newres->path = pathlen > 0 ? |
721 util_concat_path(g->path, child->name) : strdup(child->name); | 726 util_concat_path(g->path, child->name) : strdup(child->name); |
722 | 727 |
723 stack = ucx_list_prepend(stack, newres); | 728 cxListInsert(stack, 0, newres); |
724 | 729 |
725 child = child->next; | 730 child = child->next; |
726 } | 731 } |
727 } else { | 732 } else { |
728 if(structure) { | 733 if(structure) { |
735 } | 740 } |
736 | 741 |
737 if(strlen(g->path) == 0) { | 742 if(strlen(g->path) == 0) { |
738 free_getres(g); | 743 free_getres(g); |
739 } else { | 744 } else { |
740 reslist = ucx_list_append(reslist, g); | 745 cxListAdd(reslist, g); |
741 } | 746 } |
742 } | 747 } |
748 cxListDestroy(stack); | |
743 | 749 |
744 // download resources | 750 // download resources |
745 pdata.total = totalsize; | 751 pdata.total = totalsize; |
746 | 752 |
747 int ret; | 753 int ret; |
756 } | 762 } |
757 tout = tar_open(tarfile); | 763 tout = tar_open(tarfile); |
758 } else { | 764 } else { |
759 get = get_resource; | 765 get = get_resource; |
760 } | 766 } |
761 UCX_FOREACH(elm, reslist) { | 767 CxIterator i = cxListIterator(reslist); |
762 GetResource *getres = elm->data; | 768 cx_foreach(GetResource *, getres, i) { |
763 | |
764 ret = get(repo, getres, a, tout); | 769 ret = get(repo, getres, a, tout); |
765 if(ret) { | 770 if(ret) { |
766 break; | 771 break; |
767 } | 772 } |
768 } | 773 } |
772 fprintf(stderr, "tar stream broken\n"); | 777 fprintf(stderr, "tar stream broken\n"); |
773 ret = -1; | 778 ret = -1; |
774 } | 779 } |
775 } | 780 } |
776 | 781 |
777 ucx_list_free_content(reslist, free_getres); | 782 cxListDestroy(reslist); |
778 ucx_list_free(reslist); | |
779 free(path); | 783 free(path); |
780 | 784 |
781 if(pdata.out && !pdata.isstdout) { | 785 if(pdata.out && !pdata.isstdout) { |
782 fclose(pdata.out); | 786 fclose(pdata.out); |
783 } | 787 } |
1133 } | 1137 } |
1134 } | 1138 } |
1135 } | 1139 } |
1136 | 1140 |
1137 if(import) { | 1141 if(import) { |
1138 ucx_map_cstr_put(a->options, "resursive", ""); | 1142 cxMapPut(a->options, cx_hash_key_str("resursive"), ""); |
1139 } | 1143 } |
1140 | 1144 |
1141 char *url = a->argv[0]; | 1145 char *url = a->argv[0]; |
1142 char *path = NULL; | 1146 char *path = NULL; |
1143 Repository *repo = url2repo(url, &path); | 1147 Repository *repo = url2repo(url, &path); |
1156 DavBool printfile = FALSE; | 1160 DavBool printfile = FALSE; |
1157 DavBool ignoredirerr = FALSE; | 1161 DavBool ignoredirerr = FALSE; |
1158 if(a->argc > 2) { | 1162 if(a->argc > 2) { |
1159 printfile = TRUE; | 1163 printfile = TRUE; |
1160 ignoredirerr = TRUE; | 1164 ignoredirerr = TRUE; |
1161 } else if(ucx_map_cstr_get(a->options, "recursive")) { | 1165 } else if(cmd_getoption(a, "recursive")) { |
1162 printfile = TRUE; | 1166 printfile = TRUE; |
1163 } | 1167 } |
1164 | 1168 |
1165 char *finfo_str = cmd_getoption(a, "finfo"); | 1169 char *finfo_str = cmd_getoption(a, "finfo"); |
1166 uint32_t finfo = 0; | 1170 uint32_t finfo = 0; |
1287 FILE *in = sys_fopen(file, "rb"); | 1291 FILE *in = sys_fopen(file, "rb"); |
1288 if(!in) { | 1292 if(!in) { |
1289 fprintf(stderr, "cannot open input file\n"); | 1293 fprintf(stderr, "cannot open input file\n"); |
1290 return -1; | 1294 return -1; |
1291 } | 1295 } |
1292 char *filename = util_resource_name(file); | 1296 const char *filename = util_resource_name(file); |
1293 //path = util_concat_path(path, filename); | 1297 //path = util_concat_path(path, filename); |
1294 ret = put_file(repo, a, sn, path, filename, finfo, file, in, s.st_size); | 1298 ret = put_file(repo, a, sn, path, filename, finfo, file, in, s.st_size); |
1295 //free(path); | 1299 //free(path); |
1296 fclose(in); | 1300 fclose(in); |
1297 } | 1301 } |
1377 | 1381 |
1378 int put_file( | 1382 int put_file( |
1379 Repository *repo, | 1383 Repository *repo, |
1380 CmdArgs *a, | 1384 CmdArgs *a, |
1381 DavSession *sn, | 1385 DavSession *sn, |
1382 char *path, | 1386 const char *path, |
1383 char *name, | 1387 const char *name, |
1384 uint32_t finfo, | 1388 uint32_t finfo, |
1385 const char *fpath, | 1389 const char *fpath, |
1386 FILE *in, | 1390 FILE *in, |
1387 off_t len) | 1391 off_t len) |
1388 { | 1392 { |
1693 | 1697 |
1694 static size_t get_date_header_cb(void *header, int s, int n, void *data) { | 1698 static size_t get_date_header_cb(void *header, int s, int n, void *data) { |
1695 char **date_str = (char**)data; | 1699 char **date_str = (char**)data; |
1696 | 1700 |
1697 //printf("header: %.*s\n", s*n, header); | 1701 //printf("header: %.*s\n", s*n, header); |
1698 sstr_t h = sstrn(header, s*n); | 1702 cxstring h = cx_strn(header, s*n); |
1699 if(sstrprefix(h, S("Date:"))) { | 1703 if(cx_strprefix(h, CX_STR("Date:"))) { |
1700 sstr_t v = sstrsubs(h, 5); | 1704 cxstring v = cx_strsubs(h, 5); |
1701 v = sstrdup(sstrtrim(v)); | 1705 *date_str = cx_strdup(cx_strtrim(v)).ptr; |
1702 *date_str = v.ptr; | |
1703 } | 1706 } |
1704 return s*n; | 1707 return s*n; |
1705 } | 1708 } |
1706 | 1709 |
1707 int cmd_date(CmdArgs *a) { | 1710 int cmd_date(CmdArgs *a) { |
1924 | 1927 |
1925 char *url = a->argv[0]; | 1928 char *url = a->argv[0]; |
1926 char *path = NULL; | 1929 char *path = NULL; |
1927 Repository *repo = url2repo(url, &path); | 1930 Repository *repo = url2repo(url, &path); |
1928 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); | 1931 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); |
1929 ucx_mempool_reg_destr(sn->mp, path, free); | 1932 util_regdestr(sn->mp, path, free); |
1930 | 1933 |
1931 if(set_session_config(sn, a)) { | 1934 if(set_session_config(sn, a)) { |
1932 return -1; | 1935 return -1; |
1933 } | 1936 } |
1934 | 1937 |
1935 time_t timeout = 0; | 1938 time_t timeout = 0; |
1936 char *timeoutstr = cmd_getoption(a, "timeout"); | 1939 char *timeoutstr = cmd_getoption(a, "timeout"); |
1937 if(timeoutstr) { | 1940 if(timeoutstr) { |
1938 if(!sstrcasecmp(sstr(timeoutstr), S("infinite"))) { | 1941 if(!cx_strcasecmp(cx_str(timeoutstr), CX_STR("infinite"))) { |
1939 timeout = -1; | 1942 timeout = -1; |
1940 } else { | 1943 } else { |
1941 uint64_t i; | 1944 uint64_t i; |
1942 if(util_strtouint(timeoutstr, &i)) { | 1945 if(util_strtouint(timeoutstr, &i)) { |
1943 timeout = (time_t)i; | 1946 timeout = (time_t)i; |
1968 dav_session_destroy(sn); | 1971 dav_session_destroy(sn); |
1969 return 0; | 1972 return 0; |
1970 } | 1973 } |
1971 | 1974 |
1972 static char* read_line() { | 1975 static char* read_line() { |
1973 UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); | 1976 CxBuffer buf; |
1977 cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); | |
1974 int c; | 1978 int c; |
1975 while((c = getchar()) != EOF) { | 1979 while((c = getchar()) != EOF) { |
1976 if(c == '\n') { | 1980 if(c == '\n') { |
1977 break; | 1981 break; |
1978 } | 1982 } |
1979 ucx_buffer_putc(buf, c); | 1983 cxBufferPut(&buf, c); |
1980 } | 1984 } |
1981 char *str = NULL; | 1985 char *str = NULL; |
1982 sstr_t line = sstrtrim(sstrn(buf->space, buf->size)); | 1986 cxstring line = cx_strtrim(cx_strn(buf.space, buf.size)); |
1983 if(line.length != 0) { | 1987 if(line.length != 0) { |
1984 str = sstrdup(line).ptr; | 1988 str = cx_strdup(line).ptr; |
1985 } | 1989 } |
1986 ucx_buffer_free(buf); | 1990 cxBufferDestroy(&buf); |
1987 return str; | 1991 return str; |
1988 } | 1992 } |
1989 | 1993 |
1990 int cmd_unlock(CmdArgs *a) { | 1994 int cmd_unlock(CmdArgs *a) { |
1991 if(a->argc != 1) { | 1995 if(a->argc != 1) { |
1996 | 2000 |
1997 char *url = a->argv[0]; | 2001 char *url = a->argv[0]; |
1998 char *path = NULL; | 2002 char *path = NULL; |
1999 Repository *repo = url2repo(url, &path); | 2003 Repository *repo = url2repo(url, &path); |
2000 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); | 2004 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); |
2001 ucx_mempool_reg_destr(sn->mp, path, free); | 2005 util_regdestr(sn->mp, path, free); |
2002 if(set_session_config(sn, a)) { | 2006 if(set_session_config(sn, a)) { |
2003 return -1; | 2007 return -1; |
2004 } | 2008 } |
2005 | 2009 |
2006 char *locktoken = cmd_getoption(a, "lock"); | 2010 char *locktoken = cmd_getoption(a, "lock"); |
2107 last_ns = p.ns; | 2111 last_ns = p.ns; |
2108 } | 2112 } |
2109 | 2113 |
2110 DavXmlNode *xval = dav_get_property_ns(res, p.ns, p.name); | 2114 DavXmlNode *xval = dav_get_property_ns(res, p.ns, p.name); |
2111 if(dav_xml_isstring(xval)) { | 2115 if(dav_xml_isstring(xval)) { |
2112 sstr_t value = sstr(dav_xml_getstring(xval)); | 2116 cxstring value = cx_str(dav_xml_getstring(xval)); |
2113 printf(" %s: %.*s\n", p.name, (int)value.length, value.ptr); | 2117 printf(" %s: %.*s\n", p.name, (int)value.length, value.ptr); |
2114 } else { | 2118 } else { |
2115 // find some xml elements | 2119 // find some xml elements |
2116 printf(" %s: ", p.name); | 2120 printf(" %s: ", p.name); |
2117 DavXmlNode *x = xval->type == DAV_XML_ELEMENT ? xval : dav_xml_nextelm(xval); | 2121 DavXmlNode *x = xval->type == DAV_XML_ELEMENT ? xval : dav_xml_nextelm(xval); |
2317 return ret; | 2321 return ret; |
2318 } | 2322 } |
2319 | 2323 |
2320 | 2324 |
2321 char* stdin2str() { | 2325 char* stdin2str() { |
2322 UcxBuffer *buf = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); | 2326 CxBuffer buf; |
2323 size_t size = ucx_stream_copy(stdin, buf, fread, ucx_buffer_write); | 2327 cxBufferInit(&buf, NULL, 1024, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
2328 size_t size = cx_stream_copy(stdin, &buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite); | |
2324 if(size == 0) { | 2329 if(size == 0) { |
2325 ucx_buffer_free(buf); | 2330 cxBufferDestroy(&buf); |
2326 return NULL; | 2331 return NULL; |
2327 } else { | 2332 } else { |
2328 ucx_buffer_putc(buf, '\0'); | 2333 cxBufferPut(&buf, '\0'); |
2329 char *str = buf->space; | 2334 return buf.space; |
2330 free(buf); | 2335 } |
2331 return str; | 2336 } |
2332 } | 2337 |
2333 } | 2338 static void xml2str_i(DavXmlNode *node, CxBuffer *buf, int indent) { |
2334 | |
2335 static void xml2str_i(DavXmlNode *node, UcxBuffer *buf, int indent) { | |
2336 while(node) { | 2339 while(node) { |
2337 if(node->type == DAV_XML_ELEMENT) { | 2340 if(node->type == DAV_XML_ELEMENT) { |
2338 if(node->children) { | 2341 if(node->children) { |
2339 if(dav_xml_isstring(node->children)) { | 2342 if(dav_xml_isstring(node->children)) { |
2340 sstr_t s = sstrtrim(sstr(dav_xml_getstring(node->children))); | 2343 cxstring s = cx_strtrim(cx_str(dav_xml_getstring(node->children))); |
2341 ucx_bprintf( | 2344 cx_bprintf( |
2342 buf, | 2345 buf, |
2343 "%*s<%s>%.*s</%s>\n", | 2346 "%*s<%s>%.*s</%s>\n", |
2344 indent, | 2347 indent, |
2345 "", | 2348 "", |
2346 node->name, | 2349 node->name, |
2347 (int)s.length, | 2350 (int)s.length, |
2348 s.ptr, | 2351 s.ptr, |
2349 node->name); | 2352 node->name); |
2350 } else { | 2353 } else { |
2351 ucx_bprintf(buf, "%*s<%s>\n", indent, "", node->name); | 2354 cx_bprintf(buf, "%*s<%s>\n", indent, "", node->name); |
2352 xml2str_i(node->children, buf, indent+2); | 2355 xml2str_i(node->children, buf, indent+2); |
2353 ucx_bprintf(buf, "%*s</%s>\n", indent, "", node->name); | 2356 cx_bprintf(buf, "%*s</%s>\n", indent, "", node->name); |
2354 } | 2357 } |
2355 } else { | 2358 } else { |
2356 ucx_bprintf(buf, "%*s<%s />", indent, "", node->name); | 2359 cx_bprintf(buf, "%*s<%s />", indent, "", node->name); |
2357 ucx_buffer_putc(buf, '\n'); | 2360 cxBufferPut(buf, '\n'); |
2358 } | 2361 } |
2359 } else if(node->type == DAV_XML_TEXT) { | 2362 } else if(node->type == DAV_XML_TEXT) { |
2360 sstr_t val = sstrtrim(sstrn(node->content, node->contentlength)); | 2363 cxstring val = cx_strtrim(cx_strn(node->content, node->contentlength)); |
2361 if(val.length > 0) { | 2364 if(val.length > 0) { |
2362 ucx_bprintf(buf, "%*.*s", indent, (int)val.length, val.ptr); | 2365 cx_bprintf(buf, "%*.*s", indent, (int)val.length, val.ptr); |
2363 } | 2366 } |
2364 } | 2367 } |
2365 | 2368 |
2366 node = node->next; | 2369 node = node->next; |
2367 } | 2370 } |
2368 } | 2371 } |
2369 | 2372 |
2370 char* xml2str(DavXmlNode *node) { | 2373 char* xml2str(DavXmlNode *node) { |
2371 char *str = malloc(256); | 2374 CxBuffer buf; |
2372 UcxBuffer *buf = ucx_buffer_new(str, 256, UCX_BUFFER_AUTOEXTEND); | 2375 cxBufferInit(&buf, NULL, 256, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
2373 xml2str_i(node, buf, 0); | 2376 xml2str_i(node, &buf, 0); |
2374 ucx_buffer_putc(buf, 0); | 2377 cxBufferPut(&buf, 0); |
2375 char *space = buf->space; | 2378 return buf.space; |
2376 ucx_buffer_free(buf); | |
2377 return space; | |
2378 } | 2379 } |
2379 | 2380 |
2380 void printxmldoc(FILE *out, char *root, char *rootns, DavXmlNode *content) { | 2381 void printxmldoc(FILE *out, char *root, char *rootns, DavXmlNode *content) { |
2381 UcxMap *nsmap = ucx_map_new(16); | 2382 CxMap *nsmap = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
2382 | 2383 nsmap->simple_destructor = free; |
2383 ucx_map_cstr_put(nsmap, rootns, "x0"); | 2384 |
2385 cxMapPut(nsmap, cx_hash_key_str(rootns), "x0"); | |
2384 fprintf(out, "%s", "<?xml version=\"1.0\"?>\n"); | 2386 fprintf(out, "%s", "<?xml version=\"1.0\"?>\n"); |
2385 fprintf(out, "<x0:%s xmlns:x0=\"%s\">", root, rootns); | 2387 fprintf(out, "<x0:%s xmlns:x0=\"%s\">", root, rootns); |
2386 | 2388 |
2387 dav_print_node(out, (write_func)fwrite, nsmap, content); | 2389 dav_print_node(out, (cx_write_func)fwrite, nsmap, content); |
2388 | 2390 |
2389 fprintf(out, "</x0:%s>\n", root); | 2391 fprintf(out, "</x0:%s>\n", root); |
2390 | 2392 |
2391 // cleanup namespace map | 2393 // cleanup namespace map |
2392 ucx_map_cstr_remove(nsmap, rootns); | 2394 cxMapRemove(nsmap, cx_hash_key_str(rootns)); |
2393 ucx_map_free_content(nsmap, free); | 2395 cxMapDestroy(nsmap); |
2394 ucx_map_free(nsmap); | |
2395 } | 2396 } |
2396 | 2397 |
2397 | 2398 |
2398 /* ---------- config commands ---------- */ | 2399 /* ---------- config commands ---------- */ |
2399 | 2400 |
2402 char *name = assistant_getcfg("name"); | 2403 char *name = assistant_getcfg("name"); |
2403 if(!name) { | 2404 if(!name) { |
2404 fprintf(stderr, "Abort\n"); | 2405 fprintf(stderr, "Abort\n"); |
2405 return -1; | 2406 return -1; |
2406 } | 2407 } |
2407 if(get_repository(sstr(name))) { | 2408 if(get_repository(cx_str(name))) { |
2408 fprintf(stderr, "Repository %s already exists.\nAbort\n", name); | 2409 fprintf(stderr, "Repository %s already exists.\nAbort\n", name); |
2409 return -1; | 2410 return -1; |
2410 } | 2411 } |
2411 | 2412 |
2412 printf("\nSpecify the repository base url.\n"); | 2413 printf("\nSpecify the repository base url.\n"); |
2458 fprintf(stderr, "Usage: dav remove-repository <name...>\n"); | 2459 fprintf(stderr, "Usage: dav remove-repository <name...>\n"); |
2459 return -1; | 2460 return -1; |
2460 } | 2461 } |
2461 | 2462 |
2462 for(int i = 0 ; i < args->argc ; i++) { | 2463 for(int i = 0 ; i < args->argc ; i++) { |
2463 sstr_t reponame = sstr(args->argv[i]); | 2464 cxstring reponame = cx_str(args->argv[i]); |
2464 Repository* repo = get_repository(reponame); | 2465 Repository* repo = get_repository(reponame); |
2465 if(repo) { | 2466 if(repo) { |
2466 if(remove_repository(repo)) { | 2467 if(remove_repository(repo)) { |
2467 fprintf(stderr, "Cannot write config.xml\n"); | 2468 fprintf(stderr, "Cannot write config.xml\n"); |
2468 return -1; | 2469 return -1; |
2482 fprintf(stderr, "Too few arguments\n"); | 2483 fprintf(stderr, "Too few arguments\n"); |
2483 fprintf(stderr, "Usage: dav repository-url [-p] <name>\n"); | 2484 fprintf(stderr, "Usage: dav repository-url [-p] <name>\n"); |
2484 return -1; | 2485 return -1; |
2485 } | 2486 } |
2486 | 2487 |
2487 sstr_t reponame = sstr(args->argv[0]); | 2488 cxstring reponame = cx_str(args->argv[0]); |
2488 Repository* repo = get_repository(reponame); | 2489 Repository* repo = get_repository(reponame); |
2489 if(repo) { | 2490 if(repo) { |
2490 sstr_t url = sstr(repo->url); | 2491 cxstring url = cx_str(repo->url); |
2491 if(repo->user && !cmd_getoption(args, "plain")) { | 2492 if(repo->user && !cmd_getoption(args, "plain")) { |
2492 int hostindex = 0; | 2493 int hostindex = 0; |
2493 if(sstrprefix(url, S("https://"))) { | 2494 if(cx_strprefix(url, CX_STR("https://"))) { |
2494 printf("https://"); | 2495 printf("https://"); |
2495 hostindex = 8; | 2496 hostindex = 8; |
2496 } else if(sstrprefix(url, S("http://"))) { | 2497 } else if(cx_strprefix(url, CX_STR("http://"))) { |
2497 printf("http://"); | 2498 printf("http://"); |
2498 hostindex = 7; | 2499 hostindex = 7; |
2499 } | 2500 } |
2500 printf("%s", repo->user); | 2501 printf("%s", repo->user); |
2501 if(repo->password) { | 2502 if(repo->password) { |
2614 char *user = assistant_getcfg("User"); | 2615 char *user = assistant_getcfg("User"); |
2615 char *password = util_password_input("Password: "); | 2616 char *password = util_password_input("Password: "); |
2616 | 2617 |
2617 // optionally, get one or more locations | 2618 // optionally, get one or more locations |
2618 char *location = NULL; | 2619 char *location = NULL; |
2619 UcxList *locations = NULL; | 2620 CxList *locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
2621 locations->simple_destructor = free; | |
2620 while((location = assistant_getoptcfg("Location"))) { | 2622 while((location = assistant_getoptcfg("Location"))) { |
2621 locations = ucx_list_append(locations, location); | 2623 cxListAdd(locations, location); |
2622 } | 2624 } |
2623 | 2625 |
2624 int ret = 1; | 2626 int ret = 1; |
2625 if(user && password) { | 2627 if(user && password) { |
2626 pwdstore_put_index(secrets, id, locations); | 2628 pwdstore_put_index(secrets, id, locations); |
2633 | 2635 |
2634 if(id) free(id); | 2636 if(id) free(id); |
2635 if(user) free(user); | 2637 if(user) free(user); |
2636 if(password) free(password); | 2638 if(password) free(password); |
2637 | 2639 |
2638 ucx_list_free_content(locations, free); | 2640 cxListDestroy(locations); |
2639 ucx_list_free(locations); | |
2640 | 2641 |
2641 return ret; | 2642 return ret; |
2642 } | 2643 } |
2643 | 2644 |
2644 int cmd_add_user(CmdArgs *args) { | 2645 int cmd_add_user(CmdArgs *args) { |
2647 | 2648 |
2648 /* | 2649 /* |
2649 * called before the secret store is decrypted | 2650 * called before the secret store is decrypted |
2650 */ | 2651 */ |
2651 static int cmd_ss_list_users_bc(CmdArgs *Args, PwdStore *secrets, int *ret) { | 2652 static int cmd_ss_list_users_bc(CmdArgs *Args, PwdStore *secrets, int *ret) { |
2652 if(secrets->index->count == 0) { | 2653 if(secrets->index->size == 0) { |
2653 return 1; // abort, because the secret store is empty | 2654 return 1; // abort, because the secret store is empty |
2654 } | 2655 } |
2655 // set ret to 1, because decrypt could fail and this should be an error | 2656 // set ret to 1, because decrypt could fail and this should be an error |
2656 *ret = 1; | 2657 *ret = 1; |
2657 return 0; | 2658 return 0; |
2661 * called after the secret store is decrypted | 2662 * called after the secret store is decrypted |
2662 */ | 2663 */ |
2663 static int cmd_ss_list_users(CmdArgs *args, PwdStore *secrets, int *ret) { | 2664 static int cmd_ss_list_users(CmdArgs *args, PwdStore *secrets, int *ret) { |
2664 *ret = 0; | 2665 *ret = 0; |
2665 | 2666 |
2666 UcxList *list = secrets->locations; | 2667 CxList *list = secrets->locations; |
2667 for(int i=0;i<2;i++) { | 2668 for(int i=0;i<2;i++) { |
2668 UCX_FOREACH(elm, list) { | 2669 if(list) { |
2669 PwdIndexEntry *index = elm->data; | 2670 CxIterator i = cxListIterator(list); |
2670 PwdEntry *e = ucx_map_cstr_get(secrets->ids, index->id); | 2671 cx_foreach(PwdIndexEntry*, index, i) { |
2671 if(e) { | 2672 PwdEntry *e = cxMapGet(secrets->ids, cx_hash_key_str(index->id)); |
2672 printf("Id: %s\n", e->id); | 2673 if(e) { |
2673 printf("User: %s\n", e->user); | 2674 printf("Id: %s\n", e->id); |
2674 UCX_FOREACH(loc, index->locations) { | 2675 printf("User: %s\n", e->user); |
2675 char *location = loc->data; | 2676 if(index->locations) { |
2676 printf("Location: %s\n", location); | 2677 CxIterator loc_iter = cxListIterator(index->locations); |
2678 cx_foreach(char *, location, loc_iter) { | |
2679 printf("Location: %s\n", location); | |
2680 } | |
2681 printf("\n"); | |
2682 } | |
2683 } else { | |
2684 // broken index | |
2685 fprintf(stderr, | |
2686 "Warning: id '%s' not in secret store.\n", | |
2687 index->id); | |
2677 } | 2688 } |
2678 printf("\n"); | |
2679 } else { | |
2680 // broken index | |
2681 fprintf(stderr, | |
2682 "Warning: id '%s' not in secret store.\n", | |
2683 index->id); | |
2684 } | 2689 } |
2685 } | 2690 } |
2686 list = secrets->noloc; | 2691 list = secrets->noloc; |
2687 } | 2692 } |
2688 | 2693 |
2727 PwdEntry *entry = pwdstore_get(secrets, id); | 2732 PwdEntry *entry = pwdstore_get(secrets, id); |
2728 if(!entry) { | 2733 if(!entry) { |
2729 return; | 2734 return; |
2730 } | 2735 } |
2731 | 2736 |
2732 PwdIndexEntry *index = ucx_map_cstr_get(secrets->index, id); | 2737 PwdIndexEntry *index = cxMapGet(secrets->index, cx_hash_key_str(id)); |
2733 if(!index) { | 2738 if(!index) { |
2734 return; | 2739 return; |
2735 } | 2740 } |
2736 | 2741 |
2737 printf("Id: %s\n", entry->id); | 2742 printf("Id: %s\n", entry->id); |
2738 printf("User: %s\n", entry->user); | 2743 printf("User: %s\n", entry->user); |
2739 UCX_FOREACH(elm, index->locations) { | 2744 if(index->locations) { |
2740 printf("Location: %s\n", (char*)elm->data); | 2745 CxIterator loc_iter = cxListIterator(index->locations); |
2746 cx_foreach(char *, location, loc_iter) { | |
2747 printf("Location: %s\n", location); | |
2748 } | |
2741 } | 2749 } |
2742 } | 2750 } |
2743 | 2751 |
2744 static void secrets_remove_location(PwdIndexEntry *index) { | 2752 static void secrets_remove_location(PwdIndexEntry *index) { |
2745 if(!index->locations) { | 2753 if(!index->locations || index->locations->size == 0) { |
2746 printf("no locations\n"); | 2754 printf("no locations\n"); |
2747 return; | 2755 return; |
2748 } | 2756 } |
2749 | 2757 |
2750 printf("0: abort\n"); | 2758 printf("0: abort\n"); |
2751 int i = 1; | 2759 int i = 1; |
2752 UCX_FOREACH(elm, index->locations) { | 2760 CxIterator loc_iter = cxListIterator(index->locations); |
2753 printf("%d: %s\n", i, (char*)elm->data); | 2761 cx_foreach(char *, location, loc_iter) { |
2762 printf("%d: %s\n", i, location); | |
2754 i++; | 2763 i++; |
2755 } | 2764 } |
2756 | 2765 |
2757 char *input = assistant_getcfg("Choose location"); | 2766 char *input = assistant_getcfg("Choose location"); |
2758 if(!input) { | 2767 if(!input) { |
2762 int64_t ln = 0; | 2771 int64_t ln = 0; |
2763 if(util_strtoint(input, &ln) && (ln >= 0 && ln < i)) { | 2772 if(util_strtoint(input, &ln) && (ln >= 0 && ln < i)) { |
2764 if(ln == 0) { | 2773 if(ln == 0) { |
2765 return; | 2774 return; |
2766 } else { | 2775 } else { |
2767 UcxList *elm = ucx_list_get(index->locations, ln - 1); | 2776 char *location = cxListAt(index->locations, ln - 1); |
2768 if(elm) { | 2777 if(location) { |
2769 free(elm->data); | 2778 free(location); |
2770 index->locations = ucx_list_remove(index->locations, elm); | 2779 cxListRemove(index->locations, ln - 1); |
2771 } | 2780 } |
2772 } | 2781 } |
2773 } else { | 2782 } else { |
2774 printf("illegal input, choose 0 - %d\n", i-1); | 2783 printf("illegal input, choose 0 - %d\n", i-1); |
2775 secrets_remove_location(index); // try again | 2784 secrets_remove_location(index); // try again |
2781 if(!id) { | 2790 if(!id) { |
2782 fprintf(stderr, "Identifier required.\n"); | 2791 fprintf(stderr, "Identifier required.\n"); |
2783 return 1; | 2792 return 1; |
2784 } | 2793 } |
2785 PwdEntry *entry = pwdstore_get(secrets, id); | 2794 PwdEntry *entry = pwdstore_get(secrets, id); |
2786 PwdIndexEntry *index = ucx_map_cstr_get(secrets->index, id); | 2795 PwdIndexEntry *index = cxMapGet(secrets->index, cx_hash_key_str(id)); |
2787 if(!entry || !index) { | 2796 if(!entry || !index) { |
2788 fprintf(stderr, "Credentials with this id doesn't exist.\n"); | 2797 fprintf(stderr, "Credentials with this id doesn't exist.\n"); |
2789 return 1; | 2798 return 1; |
2790 } | 2799 } |
2791 | 2800 |
2835 } | 2844 } |
2836 case 2: { | 2845 case 2: { |
2837 // add location | 2846 // add location |
2838 char *location = assistant_getoptcfg("Location"); | 2847 char *location = assistant_getoptcfg("Location"); |
2839 if(location) { | 2848 if(location) { |
2840 index->locations = ucx_list_append(index->locations, location); | 2849 cxListAdd(index->locations, location); |
2841 } | 2850 } |
2842 break; | 2851 break; |
2843 } | 2852 } |
2844 case 3: { | 2853 case 3: { |
2845 // remove location | 2854 // remove location |
2846 secrets_remove_location(index); | 2855 secrets_remove_location(index); |
2847 break; | 2856 break; |
2848 } | 2857 } |
2849 case 4: { | 2858 case 4: { |
2850 // list locations | 2859 // list locations |
2851 if(!index->locations) { | 2860 if(!index->locations || index->locations->size == 0) { |
2852 printf("no locations\n"); | 2861 printf("no locations\n"); |
2853 } else { | 2862 } else { |
2854 UCX_FOREACH(elm, index->locations) { | 2863 CxIterator i = cxListIterator(index->locations); |
2855 printf("Location: %s\n", (char*)elm->data); | 2864 cx_foreach(char *, location, i) { |
2865 printf("Location: %s\n", location); | |
2856 } | 2866 } |
2857 } | 2867 } |
2858 break; | 2868 break; |
2859 } | 2869 } |
2860 case 5: { | 2870 case 5: { |
2908 return secretstore_cmd(args, FALSE, NULL, cmd_ss_set_master_pw, NULL); | 2918 return secretstore_cmd(args, FALSE, NULL, cmd_ss_set_master_pw, NULL); |
2909 } | 2919 } |
2910 | 2920 |
2911 static char** read_args_from_stdin(int *argc) { | 2921 static char** read_args_from_stdin(int *argc) { |
2912 // read stdin into buffer | 2922 // read stdin into buffer |
2913 UcxBuffer *in = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); | 2923 CxBuffer *in = cxBufferCreate(NULL, 1024, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
2914 ucx_stream_copy(stdin, in, (read_func)fread, (write_func)ucx_buffer_write); | 2924 cx_stream_copy(stdin, in, (cx_read_func)fread, (cx_write_func)cxBufferWrite); |
2915 | 2925 |
2916 // split input into lines | 2926 // split input into lines |
2917 ssize_t count = 0; | 2927 ssize_t count = 0; |
2918 sstr_t *lines = scstrsplit(scstrn(in->space, in->pos), SC("\n"), &count); | 2928 cxmutstr *lines; |
2929 count = cx_strsplit_ma(cxDefaultAllocator, cx_mutstrn(in->space, in->pos), CX_STR("\n"), INT_MAX, &lines); | |
2919 | 2930 |
2920 char **args = NULL; | 2931 char **args = NULL; |
2921 if(count > 0) { | 2932 if(count > 0) { |
2922 args = calloc(count, sizeof(char*)); | 2933 args = calloc(count, sizeof(char*)); |
2923 for(int i=0;i<count;i++) { | 2934 for(int i=0;i<count;i++) { |
2929 } else { | 2940 } else { |
2930 *argc = 0; | 2941 *argc = 0; |
2931 } | 2942 } |
2932 | 2943 |
2933 // cleanup | 2944 // cleanup |
2934 ucx_buffer_free(in); | 2945 cxBufferFree(in); |
2935 | 2946 |
2936 return args; | 2947 return args; |
2937 } | 2948 } |
2938 | 2949 |
2939 int cmd_complete(CmdArgs *args) { | 2950 int cmd_complete(CmdArgs *args) { |
2995 | 3006 |
2996 } | 3007 } |
2997 | 3008 |
2998 int shell_completion(char *cmd, CmdArgs *args, int index) { | 3009 int shell_completion(char *cmd, CmdArgs *args, int index) { |
2999 if(index == 1) { | 3010 if(index == 1) { |
3000 sstr_t prefix = { NULL, 0 }; | 3011 cxstring prefix = { NULL, 0 }; |
3001 if(cmd) { | 3012 if(cmd) { |
3002 prefix = sstr(cmd); | 3013 prefix = cx_str(cmd); |
3003 } | 3014 } |
3004 for(int i=0;;i++) { | 3015 for(int i=0;;i++) { |
3005 char *str = cmdusageinfo[i]; | 3016 char *str = cmdusageinfo[i]; |
3006 if(!str) { | 3017 if(!str) { |
3007 break; | 3018 break; |
3013 maxlen = w; | 3024 maxlen = w; |
3014 break; | 3025 break; |
3015 } | 3026 } |
3016 } | 3027 } |
3017 if(prefix.ptr) { | 3028 if(prefix.ptr) { |
3018 if(!sstrprefix(sstrn(str, maxlen), prefix)) { | 3029 if(!cx_strprefix(cx_strn(str, maxlen), prefix)) { |
3019 continue; | 3030 continue; |
3020 } | 3031 } |
3021 } | 3032 } |
3022 printf("%.*s\n", (int)maxlen, str); | 3033 printf("%.*s\n", (int)maxlen, str); |
3023 } | 3034 } |
3051 | 3062 |
3052 return 0; | 3063 return 0; |
3053 } | 3064 } |
3054 | 3065 |
3055 int url_completion(CmdArgs *args, char *u) { | 3066 int url_completion(CmdArgs *args, char *u) { |
3056 sstr_t url; | 3067 cxstring url; |
3057 url.ptr = u; | 3068 url.ptr = u; |
3058 url.length = u ? strlen(u) : 0; | 3069 url.length = u ? strlen(u) : 0; |
3059 | 3070 |
3060 // if the user wants the URL to be quoted, we conform to their wish | 3071 // if the user wants the URL to be quoted, we conform to their wish |
3061 // a null-char is an indicator, that the strings shall not be quoted | 3072 // a null-char is an indicator, that the strings shall not be quoted |
3080 repocomp = 0; | 3091 repocomp = 0; |
3081 break; | 3092 break; |
3082 } | 3093 } |
3083 } | 3094 } |
3084 if(repocomp) { | 3095 if(repocomp) { |
3085 UcxList *repos = get_repositories(); | 3096 CxIterator i = get_repositories(); |
3086 UCX_FOREACH(elm, repos) { | 3097 cx_foreach(Repository*, repo, i) { |
3087 Repository *repo = elm->data; | 3098 if(cx_strprefix(cx_str(repo->name), url)) { |
3088 if(sstrprefix(sstr(repo->name), url)) { | |
3089 if(quote == '\0') { | 3099 if(quote == '\0') { |
3090 printf("%s/\n", repo->name); | 3100 printf("%s/\n", repo->name); |
3091 } else { | 3101 } else { |
3092 printf("%c%s/%c\n", quote, repo->name, quote); | 3102 printf("%c%s/%c\n", quote, repo->name, quote); |
3093 } | 3103 } |
3094 } | 3104 } |
3095 | 3105 |
3096 } | 3106 } |
3097 } else { | 3107 } else { |
3098 // url completion | 3108 // url completion |
3099 ucx_map_cstr_put(args->options, "noinput", ""); | 3109 cxMapPut(args->options, cx_hash_key_str("noinput"), ""); |
3100 | 3110 |
3101 char *path = NULL; | 3111 char *path = NULL; |
3102 Repository *repo = url2repo_s(url, &path); | 3112 Repository *repo = url2repo_s(url, &path); |
3103 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, args); | 3113 DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, args); |
3104 if(!sn) { | 3114 if(!sn) { |
3108 return 0; | 3118 return 0; |
3109 } | 3119 } |
3110 | 3120 |
3111 size_t plen = strlen(path); | 3121 size_t plen = strlen(path); |
3112 | 3122 |
3113 sstr_t filter; | 3123 cxstring filter; |
3114 char *lspath = NULL; | 3124 char *lspath = NULL; |
3115 if(path[plen-1] == '/') { | 3125 if(path[plen-1] == '/') { |
3116 lspath = strdup(path); | 3126 lspath = strdup(path); |
3117 filter = S(""); | 3127 filter = CX_STR(""); |
3118 } else { | 3128 } else { |
3119 lspath = util_parent_path(path); | 3129 lspath = util_parent_path(path); |
3120 filter = sstr(util_resource_name(path)); | 3130 filter = cx_str(util_resource_name(path)); |
3121 } | 3131 } |
3122 | 3132 |
3123 DavResource *ls = dav_query(sn, "select - from %s order by name", lspath); | 3133 DavResource *ls = dav_query(sn, "select - from %s order by name", lspath); |
3124 DavResource *elm = ls ? ls->children : NULL; | 3134 DavResource *elm = ls ? ls->children : NULL; |
3125 while(elm) { | 3135 while(elm) { |
3126 sstr_t name = sstr(elm->name); | 3136 cxstring name = cx_str(elm->name); |
3127 if(sstrprefix(name, filter)) { | 3137 if(cx_strprefix(name, filter)) { |
3128 int space = 0; | 3138 int space = 0; |
3129 for(int i=0;i<name.length;i++) { | 3139 for(int i=0;i<name.length;i++) { |
3130 if(name.ptr[i] == ' ') { | 3140 if(name.ptr[i] == ' ') { |
3131 space = 1; | 3141 space = 1; |
3132 break; | 3142 break; |
3133 } | 3143 } |
3134 } | 3144 } |
3135 | 3145 |
3136 UcxBuffer *out = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); | 3146 CxBuffer *out = cxBufferCreate(NULL, 512, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
3137 ucx_buffer_puts(out, repo->name); | 3147 cxBufferPutString(out, repo->name); |
3138 if(space) { | 3148 if(space) { |
3139 size_t l = strlen(elm->path); | 3149 size_t l = strlen(elm->path); |
3140 for(int i=0;i<l;i++) { | 3150 for(int i=0;i<l;i++) { |
3141 // only if we do not quote, we have to escape | 3151 // only if we do not quote, we have to escape |
3142 char nextc = elm->path[i]; | 3152 char nextc = elm->path[i]; |
3143 if(quote == '\0' && NULL != strchr( | 3153 if(quote == '\0' && NULL != strchr( |
3144 "!\"#$&'()*,;<>?[\\]^`{|}~ ", nextc)) { | 3154 "!\"#$&'()*,;<>?[\\]^`{|}~ ", nextc)) { |
3145 ucx_buffer_putc(out, '\\'); | 3155 cxBufferPut(out, '\\'); |
3146 } | 3156 } |
3147 ucx_buffer_putc(out, nextc); | 3157 cxBufferPut(out, nextc); |
3148 } | 3158 } |
3149 } else { | 3159 } else { |
3150 ucx_buffer_puts(out, elm->path); | 3160 cxBufferPutString(out, elm->path); |
3151 } | 3161 } |
3152 if(elm->iscollection) { | 3162 if(elm->iscollection) { |
3153 if(out->space[out->pos-1] != '/') { | 3163 if(out->space[out->pos-1] != '/') { |
3154 ucx_buffer_putc(out, '/'); | 3164 cxBufferPut(out, '/'); |
3155 } | 3165 } |
3156 } | 3166 } |
3157 if (quote == '\0') { | 3167 if (quote == '\0') { |
3158 printf("%.*s\n", (int)out->pos, out->space); | 3168 printf("%.*s\n", (int)out->pos, out->space); |
3159 } else { | 3169 } else { |
3160 printf("%c%.*s%c\n", | 3170 printf("%c%.*s%c\n", |
3161 quote, (int)out->pos, out->space, quote); | 3171 quote, (int)out->pos, out->space, quote); |
3162 } | 3172 } |
3163 | 3173 |
3164 ucx_buffer_free(out); | 3174 cxBufferFree(out); |
3165 } | 3175 } |
3166 elm = elm->next; | 3176 elm = elm->next; |
3167 } | 3177 } |
3168 | 3178 |
3169 free(lspath); | 3179 free(lspath); |