Support git Notes.
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob3834e78e4d0ca4d47431e5d85d8bb376a5b96eb7
1 // gitdll.cpp : Defines the exported functions for the DLL application.
2 //
4 #include "stdafx.h"
5 #include "git-compat-util.h"
6 #include "msvc.h"
7 #include "gitdll.h"
8 #include "cache.h"
9 #include "commit.h"
10 #include "diff.h"
11 #include "revision.h"
12 #include "diffcore.h"
13 #include "dir.h"
14 #include "builtin.h"
15 #include "exec_cmd.h"
16 #include "cache.h"
17 #include "quote.h"
18 #include "run-command.h"
20 const char git_version_string[] = GIT_VERSION;
23 #if 0
25 // This is an example of an exported variable
26 GITDLL_API int ngitdll=0;
28 // This is an example of an exported function.
29 GITDLL_API int fngitdll(void)
31 return 42;
34 // This is the constructor of a class that has been exported.
35 // see gitdll.h for the class definition
36 Cgitdll::Cgitdll()
38 return;
40 #endif
42 extern char g_last_error[];
43 void * g_prefix;
45 char * get_git_last_error()
47 return g_last_error;
50 extern void die_dll(const char *err, va_list params);
52 void dll_entry()
54 set_die_routine(die_dll);
57 int git_get_sha1(const char *name, GIT_HASH sha1)
59 return get_sha1(name,sha1);
62 static int convert_slash(char * path)
64 while(*path)
66 if(*path == '\\' )
67 *path = '/';
68 path++;
72 int git_init()
74 char *home;
75 char path[MAX_PATH+1];
76 char *prefix;
77 int ret;
78 size_t homesize,size,httpsize;
80 _fmode = _O_BINARY;
81 _setmode(_fileno(stdin), _O_BINARY);
82 _setmode(_fileno(stdout), _O_BINARY);
83 _setmode(_fileno(stderr), _O_BINARY);
85 // set HOME if not set already
86 getenv_s(&homesize, NULL, 0, "HOME");
87 if (!homesize)
89 _dupenv_s(&home,&size,"USERPROFILE");
90 _putenv_s("HOME",home);
91 free(home);
93 GetModuleFileName(NULL, path, MAX_PATH);
94 convert_slash(path);
96 git_extract_argv0_path(path);
97 g_prefix = prefix = setup_git_directory();
98 ret = git_config(git_default_config, NULL);
100 if (!homesize)
102 _putenv_s("HOME","");/* clear home evironment to avoid affact third part software*/
105 return ret;
108 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR *author, char *pbuff)
110 char *end;
112 author->Name=pbuff;
113 end=strchr(pbuff,'<');
114 if( end == 0)
116 return -1;
118 author->NameSize = end - pbuff - 1;
120 pbuff = end +1;
121 end = strchr(pbuff, '>');
122 if( end == 0)
123 return -1;
125 author->Email = pbuff ;
126 author->EmailSize = end - pbuff;
128 pbuff = end + 2;
130 author->Date = atol(pbuff);
131 end = strchr(pbuff, ' ');
132 if( end == 0 )
133 return -1;
135 pbuff=end;
136 author->TimeZone = atol(pbuff);
138 return 0;
141 int git_parse_commit(GIT_COMMIT *commit)
143 int ret = 0;
144 char *pbuf;
145 char *end;
146 struct commit *p;
148 p= (struct commit *)commit->m_pGitCommit;
150 memcpy(commit->m_hash,p->object.sha1,GIT_HASH_SIZE);
152 commit->m_Encode = NULL;
153 commit->m_EncodeSize = 0;
155 if(p->buffer == NULL)
156 return -1;
158 pbuf = p->buffer;
159 while(pbuf)
161 if( strncmp(pbuf,"author",6) == 0)
163 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
164 if(ret)
165 return ret;
167 if( strncmp(pbuf, "committer",9) == 0)
169 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
170 if(ret)
171 return ret;
173 pbuf = strchr(pbuf,'\n');
174 if(pbuf == NULL)
175 return -1;
177 while((*pbuf) && (*pbuf == '\n'))
178 pbuf ++;
180 if( strncmp(pbuf, "encoding",8) == 0 )
182 pbuf += 9;
183 commit->m_Encode=pbuf;
184 end = strchr(pbuf,'\n');
185 commit->m_EncodeSize=end -pbuf;
187 pbuf = end +1;
188 while((*pbuf) && (*pbuf == '\n'))
189 pbuf ++;
191 commit->m_Subject=pbuf;
192 end = strchr(pbuf,'\n');
193 if( end == 0)
194 commit->m_SubjectSize = strlen(pbuf);
195 else
197 commit->m_SubjectSize = end - pbuf;
198 pbuf = end +1;
199 commit->m_Body = pbuf;
200 commit->m_BodySize = strlen(pbuf);
201 return 0;
206 pbuf = strchr(pbuf,'\n');
207 if(pbuf)
208 pbuf ++;
213 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)
215 int ret = 0;
217 struct commit *p;
219 memset(commit,0,sizeof(GIT_COMMIT));
221 commit->m_pGitCommit = p = lookup_commit(hash);
223 if(commit == NULL)
224 return -1;
226 if(p == NULL)
227 return -1;
229 ret = parse_commit(p);
230 if( ret )
231 return ret;
233 return git_parse_commit(commit);
236 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
238 struct commit *p = commit->m_pGitCommit;
240 if(list == NULL)
241 return -1;
243 *list = (GIT_COMMIT_LIST*)p->parents;
244 return 0;
246 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
248 struct commit_list *l = *(struct commit_list **)list;
249 if(list == NULL || l==NULL)
250 return -1;
252 if(hash)
253 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);
255 *list = (GIT_COMMIT_LIST *)l->next;
256 return 0;
261 int git_free_commit(GIT_COMMIT *commit)
263 struct commit *p = commit->m_pGitCommit;
265 if( p->parents)
266 free_commit_list(p->parents);
268 if( p->buffer )
270 free(p->buffer);
271 p->buffer=NULL;
272 p->object.parsed=0;
273 p->parents=0;
274 p->tree=0;
276 memset(commit,0,sizeof(GIT_COMMIT));
277 return 0;
280 char **strtoargv(char *arg, int *size)
282 int count=0;
283 char *p=arg;
284 char **argv;
286 int i=0;
287 while(*p)
289 if(*p == '\\')
290 *p='/';
291 p++;
293 p=arg;
295 while(*p)
297 if(*p == ' ')
298 count ++;
299 p++;
302 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
303 p=(char*)(argv+count+2);
305 while(*arg)
307 if(*arg == '"')
309 argv[i] = p;
310 arg++;
311 *p=*arg;
312 while(*arg && *arg!= '"')
313 *p++=*arg++;
314 *p++=0;
315 arg++;
316 i++;
317 if(*arg == 0)
318 break;
320 if(*arg != ' ')
322 argv[i]=p;
323 while(*arg && *arg !=' ')
324 *p++ = *arg++;
325 i++;
326 *p++=0;
328 if(*arg == NULL)
329 break;
330 arg++;
332 argv[i]=NULL;
333 *size = i;
334 return argv;
336 int git_open_log(GIT_LOG * handle, char * arg)
338 struct rev_info *p_Rev;
339 int size;
340 char ** argv=0;
341 int argc=0;
342 int i=0;
343 struct setup_revision_opt opt;
345 /* clear flags */
346 unsigned int obj_size = get_max_object_index();
347 for(i =0; i<obj_size; i++)
349 struct object *ob= get_indexed_object(i);
350 if(ob)
351 ob->flags=0;
354 if(arg != NULL)
355 argv = strtoargv(arg,&argc);
357 p_Rev = malloc(sizeof(struct rev_info));
358 memset(p_Rev,0,sizeof(struct rev_info));
360 if(p_Rev == NULL)
361 return -1;
363 init_revisions(p_Rev, g_prefix);
364 p_Rev->diff = 1;
366 memset(&opt, 0, sizeof(opt));
367 opt.def = "HEAD";
369 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
371 p_Rev->pPrivate = argv;
372 *handle = p_Rev;
373 return 0;
376 int git_get_log_firstcommit(GIT_LOG handle)
378 return prepare_revision_walk(handle);
381 int git_get_log_estimate_commit_count(GIT_LOG handle)
383 struct rev_info *p_Rev;
384 p_Rev=(struct rev_info *)handle;
386 return estimate_commit_count(p_Rev, p_Rev->commits);
389 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)
391 int ret =0;
393 if(commit == NULL)
394 return -1;
396 memset(commit, 0, sizeof(GIT_COMMIT));
398 commit->m_pGitCommit = get_revision(handle);
399 if( commit->m_pGitCommit == NULL)
400 return -2;
402 ret=git_parse_commit(commit);
403 if(ret)
404 return ret;
406 return 0;
409 struct notes_tree **display_notes_trees;
410 int git_close_log(GIT_LOG handle)
412 if(handle)
414 struct rev_info *p_Rev;
415 p_Rev=(struct rev_info *)handle;
416 if(p_Rev->pPrivate)
417 free(p_Rev->pPrivate);
418 free(handle);
421 free_notes(*display_notes_trees);
422 display_notes_trees = 0;
423 return 0;
426 int git_open_diff(GIT_DIFF *diff, char * arg)
428 struct rev_info *p_Rev;
429 int size;
430 char ** argv=0;
431 int argc=0;
433 if(arg != NULL)
434 argv = strtoargv(arg,&argc);
436 p_Rev = malloc(sizeof(struct rev_info));
437 memset(p_Rev,0,sizeof(struct rev_info));
439 p_Rev->pPrivate = argv;
440 *diff = (GIT_DIFF)p_Rev;
442 init_revisions(p_Rev, g_prefix);
443 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
444 p_Rev->abbrev = 0;
445 p_Rev->diff = 1;
446 argc = setup_revisions(argc, argv, p_Rev, NULL);
448 return 0;
450 int git_close_diff(GIT_DIFF handle)
452 git_diff_flush(handle);
453 if(handle)
455 struct rev_info *p_Rev;
456 p_Rev=(struct rev_info *)handle;
457 if(p_Rev->pPrivate)
458 free(p_Rev->pPrivate);
459 free(handle);
461 return 0;
463 int git_diff_flush(GIT_DIFF diff)
465 struct diff_queue_struct *q = &diff_queued_diff;
466 struct rev_info *p_Rev;
467 int i;
468 p_Rev = (struct rev_info *)diff;
470 if(q->nr == 0)
471 return 0;
473 for (i = 0; i < q->nr; i++)
474 diff_free_filepair(q->queue[i]);
476 if(q->queue)
478 free(q->queue);
479 q->queue = NULL;
480 q->nr = q->alloc = 0;
483 if (p_Rev->diffopt.close_file)
484 fclose(p_Rev->diffopt.close_file);
486 free_diffstat_info(&p_Rev->diffstat);
489 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count)
491 int ret;
492 struct rev_info *p_Rev;
493 int i;
494 struct diff_queue_struct *q = &diff_queued_diff;
496 p_Rev = (struct rev_info *)diff;
498 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
500 if(ret)
501 return ret;
503 diffcore_std(&p_Rev->diffopt);
505 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
506 for (i = 0; i < q->nr; i++) {
507 struct diff_filepair *p = q->queue[i];
508 //if (check_pair_status(p))
509 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
512 if(file)
513 *file = q;
514 if(count)
515 *count = q->nr;
517 return 0;
520 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count)
522 struct rev_info *p_Rev;
523 int ret;
524 int i;
525 struct diff_queue_struct *q = &diff_queued_diff;
527 p_Rev = (struct rev_info *)diff;
529 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
530 if( ret )
531 return ret;
533 diffcore_std(&p_Rev->diffopt);
535 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
536 for (i = 0; i < q->nr; i++) {
537 struct diff_filepair *p = q->queue[i];
538 //if (check_pair_status(p))
539 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
542 if(file)
543 *file = q;
544 if(count)
545 *count = q->nr;
546 return 0;
549 int git_get_diff_file(GIT_DIFF diff,GIT_FILE file,int i, char **newname, char ** oldname, int *status, int *IsBin, int *inc, int *dec)
551 struct diff_queue_struct *q = &diff_queued_diff;
552 struct rev_info *p_Rev;
553 p_Rev = (struct rev_info *)diff;
555 q = (struct diff_queue_struct *)file;
556 if(file == 0)
557 return -1;
558 if(i>=q->nr)
559 return -1;
561 if(newname)
562 *newname = q->queue[i]->two->path;
564 if(oldname)
565 *oldname = q->queue[i]->one->path;
567 if(status)
568 *status = q->queue[i]->status;
570 if(p_Rev->diffstat.files)
572 int j;
573 for(j=0;j<p_Rev->diffstat.nr;j++)
575 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
576 break;
578 if( j== p_Rev->diffstat.nr)
580 *IsBin=1;
581 *inc=0;
582 *dec=0;
583 return 0;
585 if(IsBin)
586 *IsBin = p_Rev->diffstat.files[j]->is_binary;
587 if(inc)
588 *inc = p_Rev->diffstat.files[j]->added;
589 if(dec)
590 *dec = p_Rev->diffstat.files[j]->deleted;
591 }else
593 *IsBin=1;
594 *inc=0;
595 *dec=0;
598 return 0;
601 int git_read_tree(GIT_HASH hash,read_tree_fn_t fn, void *context)
603 struct tree * root;
604 int ret;
605 reprepare_packed_git();
606 root = parse_tree_indirect(hash);
608 if (!root)
610 free_all_pack();
611 return -1;
613 ret = read_tree_recursive(root,NULL,NULL,0,NULL,fn,context);
614 free_all_pack();
615 return ret;
618 int git_add_exclude(const char *string, const char *base,
619 int baselen, struct exclude_list *which)
621 add_exclude(string, base, baselen, which);
622 return 0;
625 int git_create_exclude_list(EXCLUDE_LIST *which)
627 *which = malloc(sizeof(struct exclude_list));
628 memset(*which,0,sizeof(struct exclude_list));
629 return 0;
632 int git_free_exclude_list(EXCLUDE_LIST which)
634 int i=0;
635 struct exclude_list *p = (struct exclude_list *) which;
637 for(i=0; i<p->nr;i++)
639 free(p->excludes[i]);
641 free(p->excludes);
642 free(p);
645 int git_check_excluded_1(const char *pathname,
646 int pathlen, const char *basename, int *dtype,
647 EXCLUDE_LIST el)
649 return excluded_from_list(pathname, pathlen, basename,dtype,el);
652 int git_get_notes(GIT_HASH hash, char **p_note)
654 struct strbuf sb;
655 size_t size;
656 strbuf_init(&sb,0);
657 format_display_notes(hash, &sb, "utf-8", 0);
658 *p_note = strbuf_detach(&sb,&size);
660 return 0;
663 struct cmd_struct {
664 const char *cmd;
665 int (*fn)(int, const char **, const char *);
666 int option;
669 #define RUN_SETUP (1<<0)
670 #define USE_PAGER (1<<1)
672 * require working tree to be present -- anything uses this needs
673 * RUN_SETUP for reading from the configuration file.
675 #define NEED_WORK_TREE (1<<2)
677 const char git_usage_string[] =
678 "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
679 " [-p|--paginate|--no-pager] [--no-replace-objects]\n"
680 " [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
681 " [-c name=value] [--help]\n"
682 " COMMAND [ARGS]";
684 const char git_more_info_string[] =
685 "See 'git help COMMAND' for more information on a specific command.";
687 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
688 int check_pager_config(const char *cmd)
690 return 0;
694 int git_run_cmd(char *cmd, char *arg)
697 int i=0;
698 char ** argv=0;
699 int argc=0;
701 static struct cmd_struct commands[] = {
702 { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
703 { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
704 { "annotate", cmd_annotate, RUN_SETUP },
705 { "apply", cmd_apply },
706 { "archive", cmd_archive },
707 { "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE },
708 { "blame", cmd_blame, RUN_SETUP },
709 { "branch", cmd_branch, RUN_SETUP },
710 { "bundle", cmd_bundle },
711 { "cat-file", cmd_cat_file, RUN_SETUP },
712 { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
713 { "checkout-index", cmd_checkout_index,
714 RUN_SETUP | NEED_WORK_TREE},
715 { "check-ref-format", cmd_check_ref_format },
716 { "check-attr", cmd_check_attr, RUN_SETUP },
717 { "cherry", cmd_cherry, RUN_SETUP },
718 { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
719 { "clone", cmd_clone },
720 { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
721 { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
722 { "commit-tree", cmd_commit_tree, RUN_SETUP },
723 { "config", cmd_config },
724 { "count-objects", cmd_count_objects, RUN_SETUP },
725 { "describe", cmd_describe, RUN_SETUP },
726 { "diff", cmd_diff },
727 { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
728 { "diff-index", cmd_diff_index, RUN_SETUP },
729 { "diff-tree", cmd_diff_tree, RUN_SETUP },
730 { "fast-export", cmd_fast_export, RUN_SETUP },
731 { "fetch", cmd_fetch, RUN_SETUP },
732 { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
733 { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
734 { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
735 { "format-patch", cmd_format_patch, RUN_SETUP },
736 { "fsck", cmd_fsck, RUN_SETUP },
737 { "fsck-objects", cmd_fsck, RUN_SETUP },
738 { "gc", cmd_gc, RUN_SETUP },
739 { "get-tar-commit-id", cmd_get_tar_commit_id },
740 { "grep", cmd_grep },
741 { "hash-object", cmd_hash_object },
742 { "help", cmd_help },
743 { "index-pack", cmd_index_pack },
744 { "init", cmd_init_db },
745 { "init-db", cmd_init_db },
746 { "log", cmd_log, RUN_SETUP },
747 { "ls-files", cmd_ls_files, RUN_SETUP },
748 { "ls-tree", cmd_ls_tree, RUN_SETUP },
749 { "ls-remote", cmd_ls_remote },
750 { "mailinfo", cmd_mailinfo },
751 { "mailsplit", cmd_mailsplit },
752 { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
753 { "merge-base", cmd_merge_base, RUN_SETUP },
754 { "merge-file", cmd_merge_file },
755 { "merge-index", cmd_merge_index, RUN_SETUP },
756 { "merge-ours", cmd_merge_ours, RUN_SETUP },
757 { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
758 { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
759 { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
760 { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
761 { "merge-tree", cmd_merge_tree, RUN_SETUP },
762 { "mktag", cmd_mktag, RUN_SETUP },
763 { "mktree", cmd_mktree, RUN_SETUP },
764 { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
765 { "name-rev", cmd_name_rev, RUN_SETUP },
766 { "notes", cmd_notes, RUN_SETUP },
767 { "pack-objects", cmd_pack_objects, RUN_SETUP },
768 { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
769 { "patch-id", cmd_patch_id },
770 { "peek-remote", cmd_ls_remote },
771 { "pickaxe", cmd_blame, RUN_SETUP },
772 { "prune", cmd_prune, RUN_SETUP },
773 { "prune-packed", cmd_prune_packed, RUN_SETUP },
774 { "push", cmd_push, RUN_SETUP },
775 { "read-tree", cmd_read_tree, RUN_SETUP },
776 { "receive-pack", cmd_receive_pack },
777 { "reflog", cmd_reflog, RUN_SETUP },
778 { "remote", cmd_remote, RUN_SETUP },
779 { "replace", cmd_replace, RUN_SETUP },
780 { "repo-config", cmd_config },
781 { "rerere", cmd_rerere, RUN_SETUP },
782 { "reset", cmd_reset, RUN_SETUP },
783 { "rev-list", cmd_rev_list, RUN_SETUP },
784 { "rev-parse", cmd_rev_parse },
785 { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
786 { "rm", cmd_rm, RUN_SETUP },
787 { "send-pack", cmd_send_pack, RUN_SETUP },
788 { "shortlog", cmd_shortlog, USE_PAGER },
789 { "show-branch", cmd_show_branch, RUN_SETUP },
790 { "show", cmd_show, RUN_SETUP },
791 { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
792 { "stripspace", cmd_stripspace },
793 { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
794 { "tag", cmd_tag, RUN_SETUP },
795 { "tar-tree", cmd_tar_tree },
796 { "unpack-file", cmd_unpack_file, RUN_SETUP },
797 { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
798 { "update-index", cmd_update_index, RUN_SETUP },
799 { "update-ref", cmd_update_ref, RUN_SETUP },
800 { "update-server-info", cmd_update_server_info, RUN_SETUP },
801 { "upload-archive", cmd_upload_archive },
802 { "var", cmd_var },
803 { "verify-tag", cmd_verify_tag, RUN_SETUP },
804 { "version", cmd_version },
805 { "whatchanged", cmd_whatchanged, RUN_SETUP },
806 { "write-tree", cmd_write_tree, RUN_SETUP },
807 { "verify-pack", cmd_verify_pack },
808 { "show-ref", cmd_show_ref, RUN_SETUP },
809 { "pack-refs", cmd_pack_refs, RUN_SETUP },
812 git_init();
814 for(i=0;i< sizeof(commands) / sizeof(struct cmd_struct);i++)
816 if(strcmp(cmd,commands[i].cmd)==0)
818 int ret;
819 if(arg != NULL)
820 argv = strtoargv(arg,&argc);
822 ret = commands[i].fn(argc, argv, NULL);
824 if(argv)
825 free(argv);
827 return ret;
832 return -1;