complete.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include "complete.h"
  12. static int
  13. longestprefixlength(char *a, char *b, int n)
  14. {
  15. int i, w;
  16. Rune ra, rb;
  17. for(i=0; i<n; i+=w){
  18. w = chartorune(&ra, a);
  19. chartorune(&rb, b);
  20. if(ra != rb)
  21. break;
  22. a += w;
  23. b += w;
  24. }
  25. return i;
  26. }
  27. void
  28. freecompletion(Completion *c)
  29. {
  30. if(c){
  31. free(c->filename);
  32. free(c);
  33. }
  34. }
  35. static int
  36. strpcmp(const void *va, const void *vb)
  37. {
  38. char *a, *b;
  39. a = *(char**)va;
  40. b = *(char**)vb;
  41. return strcmp(a, b);
  42. }
  43. Completion*
  44. complete(char *dir, char *s)
  45. {
  46. int32_t i, l, n, nfile, len, nbytes;
  47. int fd, minlen;
  48. Dir *dirp;
  49. char **name, *p;
  50. uint32_t* mode;
  51. Completion *c;
  52. if(strchr(s, '/') != nil){
  53. werrstr("slash character in name argument to complete()");
  54. return nil;
  55. }
  56. fd = open(dir, OREAD);
  57. if(fd < 0)
  58. return nil;
  59. n = dirreadall(fd, &dirp);
  60. if(n <= 0){
  61. close(fd);
  62. return nil;
  63. }
  64. /* find longest string, for allocation */
  65. len = 0;
  66. for(i=0; i<n; i++){
  67. l = strlen(dirp[i].name) + 1 + 1; /* +1 for / +1 for \0 */
  68. if(l > len)
  69. len = l;
  70. }
  71. name = malloc(n*sizeof(char*));
  72. mode = malloc(n*sizeof(uint32_t));
  73. c = malloc(sizeof(Completion) + len);
  74. if(name == nil || mode == nil || c == nil)
  75. goto Return;
  76. memset(c, 0, sizeof(Completion));
  77. /* find the matches */
  78. len = strlen(s);
  79. nfile = 0;
  80. minlen = 1000000;
  81. for(i=0; i<n; i++)
  82. if(strncmp(s, dirp[i].name, len) == 0){
  83. name[nfile] = dirp[i].name;
  84. mode[nfile] = dirp[i].mode;
  85. if(minlen > strlen(dirp[i].name))
  86. minlen = strlen(dirp[i].name);
  87. nfile++;
  88. }
  89. if(nfile > 0) {
  90. /* report interesting results */
  91. /* trim length back to longest common initial string */
  92. for(i=1; i<nfile; i++)
  93. minlen = longestprefixlength(name[0], name[i], minlen);
  94. /* build the answer */
  95. c->complete = (nfile == 1);
  96. c->advance = c->complete || (minlen > len);
  97. c->string = (char*)(c+1);
  98. memmove(c->string, name[0]+len, minlen-len);
  99. if(c->complete)
  100. c->string[minlen++ - len] = (mode[0]&DMDIR)? '/' : ' ';
  101. c->string[minlen - len] = '\0';
  102. c->nmatch = nfile;
  103. } else {
  104. /* no match, so return all possible strings */
  105. for(i=0; i<n; i++){
  106. name[i] = dirp[i].name;
  107. mode[i] = dirp[i].mode;
  108. }
  109. nfile = n;
  110. c->nmatch = 0;
  111. }
  112. /* attach list of names */
  113. nbytes = nfile * sizeof(char*);
  114. for(i=0; i<nfile; i++)
  115. nbytes += strlen(name[i]) + 1 + 1;
  116. c->filename = malloc(nbytes);
  117. if(c->filename == nil)
  118. goto Return;
  119. p = (char*)(c->filename + nfile);
  120. for(i=0; i<nfile; i++){
  121. c->filename[i] = p;
  122. strcpy(p, name[i]);
  123. p += strlen(p);
  124. if(mode[i] & DMDIR)
  125. *p++ = '/';
  126. *p++ = '\0';
  127. }
  128. c->nfile = nfile;
  129. qsort(c->filename, c->nfile, sizeof(c->filename[0]), strpcmp);
  130. Return:
  131. free(name);
  132. free(mode);
  133. free(dirp);
  134. close(fd);
  135. return c;
  136. }