Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

451 lines
13 KiB

  1. /* $Header: /nw/tony/src/stevie/src/RCS/misccmds.c,v 1.14 89/08/06 09:50:17 tony Exp $
  2. *
  3. * Various routines to perform specific editing operations or return
  4. * useful information about the file.
  5. */
  6. #include "stevie.h"
  7. #include <io.h>
  8. #include <errno.h>
  9. static void openfwd(), openbwd();
  10. extern bool_t did_ai;
  11. /*
  12. * opencmd
  13. *
  14. * Add a blank line above or below the current line.
  15. */
  16. void
  17. opencmd(dir, can_ai)
  18. int dir;
  19. int can_ai; /* if true, consider auto-indent */
  20. {
  21. if (dir == FORWARD)
  22. openfwd(can_ai);
  23. else
  24. openbwd(can_ai);
  25. }
  26. static void
  27. openfwd(can_ai)
  28. int can_ai;
  29. {
  30. register LINE *l;
  31. LNPTR *next;
  32. register char *s; /* string to be moved to new line, if any */
  33. int newindex = 0; /* index of the cursor on the new line */
  34. /*
  35. * If we're in insert mode, we need to move the remainder of the
  36. * current line onto the new line. Otherwise the new line is left
  37. * blank.
  38. */
  39. if (State == INSERT || State == REPLACE)
  40. s = &Curschar->linep->s[Curschar->index];
  41. else
  42. s = "";
  43. if ((next = nextline(Curschar)) == NULL) /* open on last line */
  44. next = Fileend;
  45. /*
  46. * By asking for as much space as the prior line had we make sure
  47. * that we'll have enough space for any auto-indenting.
  48. */
  49. if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL)
  50. return;
  51. if (*s != NUL)
  52. strcpy(l->s, s); /* copy string to new line */
  53. else if (can_ai && P(P_AI) && !anyinput()) {
  54. char *p;
  55. /*
  56. * Copy prior line, and truncate after white space
  57. */
  58. strcpy(l->s, Curschar->linep->s);
  59. for (p = l->s; *p == ' ' || *p == TAB ;p++)
  60. ;
  61. *p = NUL;
  62. newindex = (int)(p - l->s);
  63. /*
  64. * If we just did an auto-indent, then we didn't type
  65. * anything on the prior line, and it should be truncated.
  66. */
  67. if (did_ai)
  68. Curschar->linep->s[0] = NUL;
  69. did_ai = TRUE;
  70. }
  71. /* truncate current line at cursor */
  72. if (State == INSERT || State == REPLACE)
  73. *s = NUL;
  74. Curschar->linep->next = l; /* link neighbors to new line */
  75. next->linep->prev = l;
  76. l->prev = Curschar->linep; /* link new line to neighbors */
  77. l->next = next->linep;
  78. if (next == Fileend) /* new line at end */
  79. l->num = Curschar->linep->num + LINEINC;
  80. else if ((l->prev->num) + 1 == l->next->num) /* no gap, renumber */
  81. renum();
  82. else { /* stick it in the middle */
  83. unsigned long lnum;
  84. lnum = ((long)l->prev->num + (long)l->next->num) / 2;
  85. l->num = lnum;
  86. }
  87. /*
  88. * Get the cursor to the start of the line, so that 'Cursrow'
  89. * gets set to the right physical line number for the stuff
  90. * that follows...
  91. */
  92. Curschar->index = 0;
  93. cursupdate();
  94. /*
  95. * If we're doing an open on the last logical line, then
  96. * go ahead and scroll the screen up. Otherwise, just insert
  97. * a blank line at the right place. We use calls to plines()
  98. * in case the cursor is resting on a long line.
  99. */
  100. if (Cursrow + plines(Curschar) == (Rows - 1))
  101. scrollup(1);
  102. else
  103. s_ins(Cursrow+plines(Curschar), 1);
  104. *Curschar = *nextline(Curschar); /* cursor moves down */
  105. Curschar->index = newindex;
  106. updatescreen(); /* because Botchar is now invalid... */
  107. cursupdate(); /* update Cursrow before insert */
  108. }
  109. static void
  110. openbwd(can_ai)
  111. int can_ai;
  112. {
  113. register LINE *l;
  114. LINE *prev;
  115. int newindex = 0;
  116. prev = Curschar->linep->prev;
  117. if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL)
  118. return;
  119. Curschar->linep->prev = l; /* link neighbors to new line */
  120. prev->next = l;
  121. l->next = Curschar->linep; /* link new line to neighbors */
  122. l->prev = prev;
  123. if (can_ai && P(P_AI) && !anyinput()) {
  124. char *p;
  125. /*
  126. * Copy current line, and truncate after white space
  127. */
  128. strcpy(l->s, Curschar->linep->s);
  129. for (p = l->s; *p == ' ' || *p == TAB ;p++)
  130. ;
  131. *p = NUL;
  132. newindex = (int)(p - l->s);
  133. did_ai = TRUE;
  134. }
  135. Curschar->linep = Curschar->linep->prev;
  136. Curschar->index = newindex;
  137. if (prev == Filetop->linep) /* new start of file */
  138. Filemem->linep = l;
  139. renum(); /* keep it simple - we don't do this often */
  140. cursupdate(); /* update Cursrow before insert */
  141. if (Cursrow != 0)
  142. s_ins(Cursrow, 1); /* insert a physical line */
  143. updatescreen();
  144. }
  145. int
  146. cntllines(pbegin,pend)
  147. register LNPTR *pbegin, *pend;
  148. {
  149. register LINE *lp;
  150. int lnum = 1;
  151. if (pbegin->linep && pend->linep)
  152. for (lp = pbegin->linep; lp != pend->linep ;lp = lp->next)
  153. lnum++;
  154. return(lnum);
  155. }
  156. /*
  157. * plines(p) - return the number of physical screen lines taken by line 'p'
  158. */
  159. int
  160. plines(p)
  161. LNPTR *p;
  162. {
  163. register int col = 0;
  164. register char *s;
  165. s = p->linep->s;
  166. if (*s == NUL) /* empty line */
  167. return 1;
  168. for (; *s != NUL ;s++) {
  169. if ( *s == TAB && !P(P_LS))
  170. col += P(P_TS) - (col % P(P_TS));
  171. else
  172. col += chars[(unsigned)(*s & 0xff)].ch_size;
  173. }
  174. /*
  175. * If list mode is on, then the '$' at the end of
  176. * the line takes up one extra column.
  177. */
  178. if (P(P_LS))
  179. col += 1;
  180. /*
  181. * If 'number' mode is on, add another 8.
  182. */
  183. if (P(P_NU))
  184. col += 8;
  185. return ((col + (Columns-1)) / Columns);
  186. }
  187. void
  188. fileinfo()
  189. {
  190. extern int numfiles, curfile;
  191. register long l1, l2;
  192. bool_t readonly = FALSE;
  193. if (Filename != NULL) {
  194. if((_access(Filename,2) == -1) && (errno == EACCES)) {
  195. readonly = TRUE;
  196. }
  197. }
  198. if (bufempty()) {
  199. l1 = 0;
  200. l2 = 1; /* don't div by zero */
  201. } else {
  202. l1 = cntllines(Filemem, Curschar);
  203. l2 = cntllines(Filemem, Fileend) - 1;
  204. }
  205. if (numfiles > 1)
  206. smsg("\"%s\"%s%s line %ld of %ld -- %ld %% -- (file %d of %d)",
  207. (Filename != NULL) ? Filename : "No File",
  208. Changed ? " [Modified]" : "",
  209. readonly == TRUE ? " [Read only]" : "",
  210. l1, l2, (l1 * 100)/l2,
  211. curfile+1, numfiles);
  212. else
  213. smsg("\"%s\"%s%s line %ld of %ld -- %ld %% --",
  214. (Filename != NULL) ? Filename : "No File",
  215. Changed ? " [Modified]" : "",
  216. readonly == TRUE ? " [Read only]" : "",
  217. l1, l2, (l1 * 100)/l2);
  218. }
  219. /*
  220. * gotoline(n) - return a pointer to line 'n'
  221. *
  222. * Returns a pointer to the last line of the file if n is zero, or
  223. * beyond the end of the file.
  224. */
  225. LNPTR *
  226. gotoline(n)
  227. register int n;
  228. {
  229. static LNPTR l;
  230. l.index = 0;
  231. if ( n == 0 )
  232. l = *prevline(Fileend);
  233. else {
  234. LNPTR *p;
  235. for (l = *Filemem; --n > 0 ;l = *p)
  236. if ((p = nextline(&l)) == NULL)
  237. break;
  238. }
  239. return &l;
  240. }
  241. void
  242. inschar(c)
  243. int c;
  244. {
  245. register char *p, *pend;
  246. /* make room for the new char. */
  247. if ( ! canincrease(1) )
  248. return;
  249. if (State != REPLACE) {
  250. p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
  251. pend = &Curschar->linep->s[Curschar->index];
  252. for (; p > pend ;p--)
  253. *p = *(p-1);
  254. *p = (char)c;
  255. } else { /* replace mode */
  256. /*
  257. * Once we reach the end of the line, we are effectively
  258. * inserting new text, so make sure the string terminator
  259. * stays out there.
  260. */
  261. if (gchar(Curschar) == NUL)
  262. Curschar->linep->s[Curschar->index+1] = NUL;
  263. pchar(Curschar, c);
  264. }
  265. /*
  266. * If we're in insert mode and showmatch mode is set, then
  267. * check for right parens and braces. If there isn't a match,
  268. * then beep. If there is a match AND it's on the screen, then
  269. * flash to it briefly. If it isn't on the screen, don't do anything.
  270. */
  271. if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
  272. LNPTR *lpos, csave;
  273. if ((lpos = showmatch()) == NULL) /* no match, so beep */
  274. beep();
  275. else if (LINEOF(lpos) >= LINEOF(Topchar)) {
  276. updatescreen(); /* show the new char first */
  277. csave = *Curschar;
  278. *Curschar = *lpos; /* move to matching char */
  279. cursupdate();
  280. windgoto(Cursrow, Curscol);
  281. delay(); /* brief pause */
  282. *Curschar = csave; /* restore cursor position */
  283. cursupdate();
  284. }
  285. }
  286. inc(Curschar);
  287. CHANGED;
  288. }
  289. bool_t
  290. delchar(fixpos)
  291. bool_t fixpos; /* if TRUE, fix the cursor position when done */
  292. {
  293. register int i;
  294. /* Check for degenerate case; there's nothing in the file. */
  295. if (bufempty())
  296. return FALSE;
  297. if (lineempty()) /* can't do anything */
  298. return FALSE;
  299. /* Delete the char. at Curschar by shifting everything */
  300. /* in the line down. */
  301. for ( i=Curschar->index+1; i < Curschar->linep->size ;i++)
  302. Curschar->linep->s[i-1] = Curschar->linep->s[i];
  303. /* If we just took off the last character of a non-blank line, */
  304. /* we don't want to end up positioned at the newline. */
  305. if (fixpos) {
  306. if (gchar(Curschar)==NUL && Curschar->index>0 && State!=INSERT)
  307. Curschar->index--;
  308. }
  309. CHANGED;
  310. return TRUE;
  311. }
  312. void
  313. delline(nlines, can_update)
  314. int nlines;
  315. bool_t can_update;
  316. {
  317. register LINE *p, *q;
  318. int dlines = 0;
  319. bool_t do_update = FALSE;
  320. while ( nlines-- > 0 ) {
  321. if (bufempty()) /* nothing to delete */
  322. break;
  323. if (buf1line()) { /* just clear the line */
  324. Curschar->linep->s[0] = NUL;
  325. Curschar->index = 0;
  326. break;
  327. }
  328. p = Curschar->linep->prev;
  329. q = Curschar->linep->next;
  330. if (p == Filetop->linep) { /* first line of file so... */
  331. Filemem->linep = q; /* adjust start of file */
  332. Topchar->linep = q; /* and screen */
  333. }
  334. p->next = q;
  335. if (q)
  336. q->prev = p;
  337. clrmark(Curschar->linep); /* clear marks for the line */
  338. /*
  339. * Delete the correct number of physical lines on the screen
  340. */
  341. if (can_update) {
  342. do_update = TRUE;
  343. dlines += plines(Curschar);
  344. }
  345. /*
  346. * If deleting the top line on the screen, adjust Topchar
  347. */
  348. if (Topchar->linep == Curschar->linep)
  349. Topchar->linep = q;
  350. free(Curschar->linep->s);
  351. free((char *) Curschar->linep);
  352. Curschar->linep = q;
  353. Curschar->index = 0; /* is this right? */
  354. CHANGED;
  355. /* If we delete the last line in the file, back up */
  356. if ( Curschar->linep == Fileend->linep) {
  357. Curschar->linep = Curschar->linep->prev;
  358. /* and don't try to delete any more lines */
  359. break;
  360. }
  361. }
  362. if(do_update) {
  363. s_del(Cursrow, dlines);
  364. }
  365. }