address.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 "sam.h"
  10. #include "parse.h"
  11. Address addr;
  12. String lastpat;
  13. int patset;
  14. File *menu;
  15. File *matchfile(String*);
  16. Address charaddr(Posn, Address, int);
  17. Address
  18. address(Addr *ap, Address a, int sign)
  19. {
  20. File *f = a.f;
  21. Address a1, a2;
  22. do{
  23. switch(ap->type){
  24. case 'l':
  25. case '#':
  26. a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign);
  27. break;
  28. case '.':
  29. a = f->dot;
  30. break;
  31. case '$':
  32. a.r.p1 = a.r.p2 = f->Buffer.nc;
  33. break;
  34. case '\'':
  35. a.r = f->mark;
  36. break;
  37. case '?':
  38. sign = -sign;
  39. if(sign == 0)
  40. sign = -1;
  41. /* fall through */
  42. case '/':
  43. nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign);
  44. a.r = sel.p[0];
  45. break;
  46. case '"':
  47. a = matchfile(ap->are)->dot;
  48. f = a.f;
  49. if(f->unread)
  50. load(f);
  51. break;
  52. case '*':
  53. a.r.p1 = 0, a.r.p2 = f->Buffer.nc;
  54. return a;
  55. case ',':
  56. case ';':
  57. if(ap->left)
  58. a1 = address(ap->left, a, 0);
  59. else
  60. a1.f = a.f, a1.r.p1 = a1.r.p2 = 0;
  61. if(ap->type == ';'){
  62. f = a1.f;
  63. a = a1;
  64. f->dot = a1;
  65. }
  66. if(ap->next)
  67. a2 = address(ap->next, a, 0);
  68. else
  69. a2.f = a.f, a2.r.p1 = a2.r.p2 = f->Buffer.nc;
  70. if(a1.f != a2.f)
  71. error(Eorder);
  72. a.f = a1.f, a.r.p1 = a1.r.p1, a.r.p2 = a2.r.p2;
  73. if(a.r.p2 < a.r.p1)
  74. error(Eorder);
  75. return a;
  76. case '+':
  77. case '-':
  78. sign = 1;
  79. if(ap->type == '-')
  80. sign = -1;
  81. if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-')
  82. a = lineaddr(1L, a, sign);
  83. break;
  84. default:
  85. panic("address");
  86. return a;
  87. }
  88. }while(ap = ap->next); /* assign = */
  89. return a;
  90. }
  91. void
  92. nextmatch(File *f, String *r, Posn p, int sign)
  93. {
  94. compile(r);
  95. if(sign >= 0){
  96. if(!execute(f, p, INFINITY))
  97. error(Esearch);
  98. if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p1==p){
  99. if(++p>f->Buffer.nc)
  100. p = 0;
  101. if(!execute(f, p, INFINITY))
  102. panic("address");
  103. }
  104. }else{
  105. if(!bexecute(f, p))
  106. error(Esearch);
  107. if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p2==p){
  108. if(--p<0)
  109. p = f->Buffer.nc;
  110. if(!bexecute(f, p))
  111. panic("address");
  112. }
  113. }
  114. }
  115. File *
  116. matchfile(String *r)
  117. {
  118. File *f;
  119. File *match = 0;
  120. int i;
  121. for(i = 0; i<file.nused; i++){
  122. f = file.filepptr[i];
  123. if(f == cmd)
  124. continue;
  125. if(filematch(f, r)){
  126. if(match)
  127. error(Emanyfiles);
  128. match = f;
  129. }
  130. }
  131. if(!match)
  132. error(Efsearch);
  133. return match;
  134. }
  135. int
  136. filematch(File *f, String *r)
  137. {
  138. char *c, buf[STRSIZE+100];
  139. String *t;
  140. c = Strtoc(&f->name);
  141. sprint(buf, "%c%c%c %s\n", " '"[f->mod],
  142. "-+"[f->rasp!=0], " ."[f==curfile], c);
  143. free(c);
  144. t = tmpcstr(buf);
  145. Strduplstr(&genstr, t);
  146. freetmpstr(t);
  147. /* A little dirty... */
  148. if(menu == 0)
  149. menu = fileopen();
  150. bufreset(&menu->Buffer);
  151. bufinsert(&menu->Buffer, 0, genstr.s, genstr.n);
  152. compile(r);
  153. return execute(menu, 0, menu->Buffer.nc);
  154. }
  155. Address
  156. charaddr(Posn l, Address addr, int sign)
  157. {
  158. if(sign == 0)
  159. addr.r.p1 = addr.r.p2 = l;
  160. else if(sign < 0)
  161. addr.r.p2 = addr.r.p1-=l;
  162. else if(sign > 0)
  163. addr.r.p1 = addr.r.p2+=l;
  164. if(addr.r.p1<0 || addr.r.p2>addr.f->Buffer.nc)
  165. error(Erange);
  166. return addr;
  167. }
  168. Address
  169. lineaddr(Posn l, Address addr, int sign)
  170. {
  171. int n;
  172. int c;
  173. File *f = addr.f;
  174. Address a;
  175. Posn p;
  176. a.f = f;
  177. if(sign >= 0){
  178. if(l == 0){
  179. if(sign==0 || addr.r.p2==0){
  180. a.r.p1 = a.r.p2 = 0;
  181. return a;
  182. }
  183. a.r.p1 = addr.r.p2;
  184. p = addr.r.p2-1;
  185. }else{
  186. if(sign==0 || addr.r.p2==0){
  187. p = (Posn)0;
  188. n = 1;
  189. }else{
  190. p = addr.r.p2-1;
  191. n = filereadc(f, p++)=='\n';
  192. }
  193. while(n < l){
  194. if(p >= f->Buffer.nc)
  195. error(Erange);
  196. if(filereadc(f, p++) == '\n')
  197. n++;
  198. }
  199. a.r.p1 = p;
  200. }
  201. while(p < f->Buffer.nc && filereadc(f, p++)!='\n')
  202. ;
  203. a.r.p2 = p;
  204. }else{
  205. p = addr.r.p1;
  206. if(l == 0)
  207. a.r.p2 = addr.r.p1;
  208. else{
  209. for(n = 0; n<l; ){ /* always runs once */
  210. if(p == 0){
  211. if(++n != l)
  212. error(Erange);
  213. }else{
  214. c = filereadc(f, p-1);
  215. if(c != '\n' || ++n != l)
  216. p--;
  217. }
  218. }
  219. a.r.p2 = p;
  220. if(p > 0)
  221. p--;
  222. }
  223. while(p > 0 && filereadc(f, p-1)!='\n') /* lines start after a newline */
  224. p--;
  225. a.r.p1 = p;
  226. }
  227. return a;
  228. }