addr.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. enum
  14. {
  15. None = 0,
  16. Fore = '+',
  17. Back = '-',
  18. };
  19. enum
  20. {
  21. Char,
  22. Line,
  23. };
  24. int
  25. isaddrc(int r)
  26. {
  27. if(r && utfrune("0123456789+-/$.#,;", r)!=nil)
  28. return TRUE;
  29. return FALSE;
  30. }
  31. /*
  32. * quite hard: could be almost anything but white space, but we are a little conservative,
  33. * aiming for regular expressions of alphanumerics and no white space
  34. */
  35. int
  36. isregexc(int r)
  37. {
  38. if(r == 0)
  39. return FALSE;
  40. if(isalnum(r))
  41. return TRUE;
  42. if(utfrune("^+-.*?#,;[]()$", r)!=nil)
  43. return TRUE;
  44. return FALSE;
  45. }
  46. Range
  47. number(Mntdir *md, Text *t, Range r, int line, int dir, int size, int *evalp)
  48. {
  49. uint q0, q1;
  50. if(size == Char){
  51. if(dir == Fore)
  52. line = r.q1+line;
  53. else if(dir == Back){
  54. if(r.q0==0 && line>0)
  55. r.q0 = t->file->nc;
  56. line = r.q0 - line;
  57. }
  58. if(line<0 || line>t->file->nc)
  59. goto Rescue;
  60. *evalp = TRUE;
  61. return (Range){line, line};
  62. }
  63. q0 = r.q0;
  64. q1 = r.q1;
  65. switch(dir){
  66. case None:
  67. q0 = 0;
  68. q1 = 0;
  69. Forward:
  70. while(line>0 && q1<t->file->nc)
  71. if(textreadc(t, q1++) == '\n' || q1==t->file->nc)
  72. if(--line > 0)
  73. q0 = q1;
  74. if(line > 0)
  75. goto Rescue;
  76. break;
  77. case Fore:
  78. if(q1 > 0)
  79. while(textreadc(t, q1-1) != '\n')
  80. q1++;
  81. q0 = q1;
  82. goto Forward;
  83. case Back:
  84. if(q0 < t->file->nc)
  85. while(q0>0 && textreadc(t, q0-1)!='\n')
  86. q0--;
  87. q1 = q0;
  88. while(line>0 && q0>0){
  89. if(textreadc(t, q0-1) == '\n'){
  90. if(--line >= 0)
  91. q1 = q0;
  92. }
  93. --q0;
  94. }
  95. if(line > 0)
  96. goto Rescue;
  97. while(q0>0 && textreadc(t, q0-1)!='\n')
  98. --q0;
  99. }
  100. *evalp = TRUE;
  101. return (Range){q0, q1};
  102. Rescue:
  103. if(md != nil)
  104. warning(nil, "address out of range\n");
  105. *evalp = FALSE;
  106. return r;
  107. }
  108. Range
  109. regexp(Mntdir *md, Text *t, Range lim, Range r, Rune *pat, int dir, int *foundp)
  110. {
  111. int found;
  112. Rangeset sel;
  113. int q;
  114. if(pat[0] == '\0' && rxnull()){
  115. warning(md, "no previous regular expression\n");
  116. *foundp = FALSE;
  117. return r;
  118. }
  119. if(pat[0] && rxcompile(pat) == FALSE){
  120. *foundp = FALSE;
  121. return r;
  122. }
  123. if(dir == Back)
  124. found = rxbexecute(t, r.q0, &sel);
  125. else{
  126. if(lim.q0 < 0)
  127. q = Infinity;
  128. else
  129. q = lim.q1;
  130. found = rxexecute(t, nil, r.q1, q, &sel);
  131. }
  132. if(!found && md==nil)
  133. warning(nil, "no match for regexp\n");
  134. *foundp = found;
  135. return sel.r[0];
  136. }
  137. Range
  138. address(Mntdir *md, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
  139. {
  140. int dir, size, npat;
  141. int prevc, c, nc, n;
  142. uint q;
  143. Rune *pat;
  144. Range r, nr;
  145. r = ar;
  146. q = q0;
  147. dir = None;
  148. size = Line;
  149. c = 0;
  150. while(q < q1){
  151. prevc = c;
  152. c = (*getc)(a, q++);
  153. switch(c){
  154. default:
  155. *qp = q-1;
  156. return r;
  157. case ';':
  158. ar = r;
  159. /* fall through */
  160. case ',':
  161. if(prevc == 0) /* lhs defaults to 0 */
  162. r.q0 = 0;
  163. if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
  164. r.q1 = t->file->nc;
  165. else{
  166. nr = address(md, t, lim, ar, a, q, q1, getc, evalp, &q);
  167. r.q1 = nr.q1;
  168. }
  169. *qp = q;
  170. return r;
  171. case '+':
  172. case '-':
  173. if(*evalp && (prevc=='+' || prevc=='-'))
  174. if((nc=(*getc)(a, q))!='#' && nc!='/' && nc!='?')
  175. r = number(md, t, r, 1, prevc, Line, evalp); /* do previous one */
  176. dir = c;
  177. break;
  178. case '.':
  179. case '$':
  180. if(q != q0+1){
  181. *qp = q-1;
  182. return r;
  183. }
  184. if(*evalp)
  185. if(c == '.')
  186. r = ar;
  187. else
  188. r = (Range){t->file->nc, t->file->nc};
  189. if(q < q1)
  190. dir = Fore;
  191. else
  192. dir = None;
  193. break;
  194. case '#':
  195. if(q==q1 || (c=(*getc)(a, q++))<'0' || '9'<c){
  196. *qp = q-1;
  197. return r;
  198. }
  199. size = Char;
  200. /* fall through */
  201. case '0': case '1': case '2': case '3': case '4':
  202. case '5': case '6': case '7': case '8': case '9':
  203. n = c -'0';
  204. while(q<q1){
  205. c = (*getc)(a, q++);
  206. if(c<'0' || '9'<c){
  207. q--;
  208. break;
  209. }
  210. n = n*10+(c-'0');
  211. }
  212. if(*evalp)
  213. r = number(md, t, r, n, dir, size, evalp);
  214. dir = None;
  215. size = Line;
  216. break;
  217. case '?':
  218. dir = Back;
  219. /* fall through */
  220. case '/':
  221. npat = 0;
  222. pat = nil;
  223. while(q<q1){
  224. c = (*getc)(a, q++);
  225. switch(c){
  226. case '\n':
  227. --q;
  228. goto out;
  229. case '\\':
  230. pat = runerealloc(pat, npat+1);
  231. pat[npat++] = c;
  232. if(q == q1)
  233. goto out;
  234. c = (*getc)(a, q++);
  235. break;
  236. case '/':
  237. goto out;
  238. }
  239. pat = runerealloc(pat, npat+1);
  240. pat[npat++] = c;
  241. }
  242. out:
  243. pat = runerealloc(pat, npat+1);
  244. pat[npat] = 0;
  245. if(*evalp)
  246. r = regexp(md, t, lim, r, pat, dir, evalp);
  247. free(pat);
  248. dir = None;
  249. size = Line;
  250. break;
  251. }
  252. }
  253. if(*evalp && dir != None)
  254. r = number(md, t, r, 1, dir, Line, evalp); /* do previous one */
  255. *qp = q;
  256. return r;
  257. }