address.c 3.9 KB

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