main.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /* main.c, Ait, BSD 3-Clause, Kevin Bloom, 2023-2024,
  2. Derived from: Atto January 2017
  3. Derived from: Anthony's Editor January 93
  4. */
  5. #include "header.h"
  6. #include "termbox.h"
  7. #include "util.h"
  8. int done;
  9. point_t nscrap;
  10. char_t *scrap;
  11. char_t *input;
  12. int msgflag;
  13. char msgline[TEMPBUF];
  14. char temp[TEMPBUF];
  15. char *gtemp = NULL;
  16. char searchtext[STRBUF_M];
  17. char replace[STRBUF_M];
  18. int found_point = -1;
  19. int search_dir = 1;
  20. int universal_argument = 0;
  21. int numeric_argument = 0;
  22. int negated = FALSE;
  23. int submatch = 0;
  24. uint32_t input_char = 0;
  25. int undoset_flag = FALSE;
  26. char editor_dir[PATH_MAX+1];
  27. int record_input = FALSE;
  28. int record_buffer_index = 0;
  29. int run_buffer_index = 0;
  30. struct tb_event record_buffer[256];
  31. int execute_kbd_macro = FALSE;
  32. int undo_index = -1;
  33. char unicode_buf[7];
  34. char character[1];
  35. int lastcommand = KBD_DEFAULT;
  36. int currentcommand = KBD_DEFAULT;
  37. int window_mode = WINDOW_DEFAULT;
  38. int ignorenotbound = FALSE;
  39. keymap_t *key_return;
  40. keymap_t *key_map;
  41. buffer_t *curbp; /* current buffer */
  42. buffer_t *bheadp; /* head of list of buffers */
  43. window_t *curwp;
  44. window_t *wheadp;
  45. buffer_t *lastbp = NULL; /* last active buffer */
  46. int LINES;
  47. int COLS;
  48. int MSGLINE;
  49. static void graceful_exit()
  50. {
  51. tb_shutdown();
  52. exit(1);
  53. }
  54. static void cont()
  55. {
  56. tb_init();
  57. LINES = tb_height();
  58. COLS = tb_width();
  59. MSGLINE = LINES-1;
  60. tb_set_input_mode(TB_INPUT_ALT);
  61. tb_clear();
  62. redraw();
  63. }
  64. static void setup_signal_handlers()
  65. {
  66. struct sigaction action;
  67. memset(&action, 0, sizeof(struct sigaction));
  68. action.sa_handler = graceful_exit;
  69. sigaction(SIGTERM, &action, NULL);
  70. sigaction(SIGINT, &action, NULL);
  71. sigaction(SIGQUIT, &action, NULL);
  72. sigaction(SIGHUP, &action, NULL);
  73. action.sa_handler = cont;
  74. sigaction(SIGCONT, &action, NULL);
  75. signal(SIGPIPE, SIG_IGN);
  76. }
  77. int main(int argc, char **argv)
  78. {
  79. int ret, u, buffers = 0;
  80. int line = 0, current = 0, lastln = 0;
  81. point_t p;
  82. if(1 < argc && argv[1][0] == '-') {
  83. if(argv[1][1] == 'v') {
  84. fprintf(stderr, "%s\n", VERSION);
  85. exit(0);
  86. }
  87. if(argv[1][1] == 'h') {
  88. fprintf(stderr, "%s\n\nUsage: ait [options] [file]... +/-line...\n\n\n-h Print help and exit\n-v Print version and exit\n", VERSION);
  89. exit(0);
  90. }
  91. }
  92. ret = tb_init();
  93. LINES = tb_height();
  94. COLS = tb_width();
  95. MSGLINE = LINES-1;
  96. character[0] = '\0';
  97. if (ret) {
  98. fprintf(stderr, "Failed with error code %d", ret);
  99. exit(1);
  100. }
  101. getcwd(editor_dir, sizeof(editor_dir));
  102. strcat(editor_dir, "/");
  103. tb_set_input_mode(TB_INPUT_ALT);
  104. tb_clear();
  105. setup_signal_handlers();
  106. if (1 < argc) {
  107. for(int v = 1; v < argc; v++) {
  108. buffers++;
  109. curbp = find_buffer(argv[v], TRUE);
  110. (void) insert_file(argv[v], FALSE);
  111. /* Save filename regardless of load() success. */
  112. if(argv[v][0] == '/') {
  113. strncpy(curbp->b_fname, argv[v], PATH_MAX);
  114. } else {
  115. strncpy(curbp->b_fname, editor_dir, PATH_MAX);
  116. strcat(curbp->b_fname, argv[v]);
  117. cleanup_path(curbp->b_fname, curbp->b_fname);
  118. }
  119. curbp->b_fname[PATH_MAX] = '\0'; /* force truncation */
  120. curbp->b_path = TRUE;
  121. curbp->b_line = 1;
  122. curbp->b_pcol = 0;
  123. if (!growgap(curbp, CHUNK))
  124. fatal("%s: Failed to allocate required memory.\n");
  125. movegap(curbp, 0);
  126. if(argv[v+1]) {
  127. if(argv[v+1][0] == '-' || argv[v+1][0] == '+') {
  128. if(argv[v+1][0] == '+') {
  129. argv[v+1]++;
  130. line = atoi(argv[v+1]);
  131. } else {
  132. argv[v+1]++;
  133. get_line_stats(&current, &lastln, curbp);
  134. line = lastln - atoi(argv[v+1]);
  135. if(line < 0)
  136. line = 0;
  137. }
  138. p = line_to_point(line);
  139. if (p != -1) {
  140. curbp->b_point = p;
  141. curbp->b_opoint = p;
  142. curbp->b_cpoint = p;
  143. if (curbp->b_epage < pos(curbp, curbp->b_ebuf)) curbp->b_reframe = 1;
  144. curbp->b_line = line;
  145. msg("Line %d", line);
  146. } else {
  147. msg("Line %d, not found", line);
  148. }
  149. v++;
  150. }
  151. }
  152. }
  153. } else {
  154. curbp = find_buffer("*scratch*", TRUE);
  155. strncpy(curbp->b_bname, "*scratch*", STRBUF_S);
  156. curbp->b_path = FALSE;
  157. }
  158. key_map = keymap;
  159. submatch = 0;
  160. wheadp = curwp = new_window();
  161. associate_b2w(curbp, curwp);
  162. one_window(curwp);
  163. if(buffers > 1) {
  164. chop_window();
  165. if(curbp->b_next == NULL)
  166. next_buffer();
  167. }
  168. while (!done) {
  169. update_display();
  170. if(curwp->w_recenter) {
  171. recenter();
  172. curwp->w_recenter = FALSE;
  173. update_display();
  174. }
  175. curbp->b_opoint = curbp->b_point;
  176. input = get_key(key_map, &key_return);
  177. if (key_return != NULL) {
  178. /* TODO: a better way to figure out editing commands */
  179. if((key_return->key_desc[2] == 'd' || key_return->key_desc[4] == '%' ||
  180. key_return->key_desc[2] == 'i' || key_return->key_desc[2] == 'k' ||
  181. key_return->key_desc[2] == '/' || key_return->key_desc[2] == 'm' ||
  182. key_return->key_desc[2] == 't' || key_return->key_desc[2] == 'y' ||
  183. key_return->key_desc[4] == 'd' || key_return->key_desc[4] == 'i' ||
  184. key_return->key_desc[4] == 't' || key_return->key_desc[4] == 'x' ||
  185. key_return->key_desc[4] == 'k' || key_return->key_desc[4] == '/' ||
  186. key_return->key_desc[4] == 'l' || key_return->key_desc[4] == 'c' ||
  187. key_return->key_desc[4] == 'u' || key_return->key_desc[4] == 'z' ||
  188. key_return->key_desc[4] == 'Z' || (key_return->key_desc[4] == 'b'
  189. && key_return->key_desc[5] == 'k') || key_return->key_desc[2] == 'h') &&
  190. is_file_modified(curbp->b_fname)) {
  191. if(!file_was_modified_prompt()) {
  192. continue;
  193. }
  194. }
  195. submatch = 0;
  196. if(execute_kbd_macro) {
  197. (key_return->func)();
  198. } else {
  199. u = numeric_argument > 0 ? numeric_argument : power(4, universal_argument);
  200. if(numeric_argument > 0 &&
  201. key_return->universal_argument_action != UA_PREVENT)
  202. key_return->universal_argument_action = UA_REPEAT;
  203. switch(key_return->universal_argument_action) {
  204. case UA_REPEAT:
  205. for(; u > 0; u--)
  206. (key_return->func)();
  207. universal_argument = 0;
  208. numeric_argument = 0;
  209. /* For gotochar */
  210. character[0] = '\0';
  211. if(curbp->b_point > curbp->b_epage || curbp->b_point < curbp->b_page)
  212. curbp->b_reframe = TRUE;
  213. break;
  214. default:
  215. (key_return->func)();
  216. break;
  217. }
  218. }
  219. if(temp[0] != 0)
  220. memset(temp, 0, TEMPBUF);
  221. } else if(submatch > 0) {
  222. // do nothing
  223. } else {
  224. submatch = 0;
  225. if((unicode_buf[0] != '\0' || *input > 31 || *input == 13 || *input == 9)
  226. && is_file_modified(curbp->b_fname)) {
  227. if(!file_was_modified_prompt()) {
  228. continue;
  229. }
  230. }
  231. if(unicode_buf[0] != '\0') {
  232. if(!execute_kbd_macro)
  233. u = numeric_argument > 0 ? numeric_argument : power(4, universal_argument);
  234. else
  235. u = 1;
  236. char tempbuf[7];
  237. strncpy(tempbuf, unicode_buf, 7);
  238. for(; u > 0; u--) {
  239. unicode_buf[0] = tempbuf[0];
  240. insert_unicode();
  241. }
  242. if(!execute_kbd_macro)
  243. numeric_argument = 0;
  244. }
  245. else if(!ignorenotbound)
  246. msg("Not bound");
  247. else if(ignorenotbound) {
  248. msg("");
  249. ignorenotbound = FALSE;
  250. }
  251. }
  252. /* For gotochar */
  253. character[0] = '\0';
  254. if(currentcommand != KBD_DELETE_CHAR &&
  255. currentcommand != KBD_CUT &&
  256. currentcommand != KBD_UNDO
  257. ) {
  258. if(curbp->b_opoint > curbp->b_point) {
  259. curbp->b_opoint--;
  260. while(curbp->b_opoint >= curbp->b_point) {
  261. if(*ptr(curbp, curbp->b_opoint) == '\n')
  262. curbp->b_line--;
  263. curbp->b_opoint--;
  264. }
  265. } else if(curbp->b_opoint < curbp->b_point) {
  266. while(curbp->b_opoint < curbp->b_point) {
  267. if(*ptr(curbp, curbp->b_opoint) == '\n')
  268. curbp->b_line++;
  269. curbp->b_opoint++;
  270. }
  271. }
  272. }
  273. if(currentcommand != lastcommand)
  274. lastcommand = currentcommand;
  275. currentcommand = KBD_DEFAULT;
  276. }
  277. if (scrap != NULL) free(scrap);
  278. tb_set_cursor(0, LINES-1);
  279. tb_present();
  280. tb_shutdown();
  281. return 0;
  282. }
  283. void fatal(char *msg)
  284. {
  285. tb_present();
  286. fprintf(stderr, msg, PROG_NAME);
  287. exit(1);
  288. }
  289. void msg(char *msg, ...)
  290. {
  291. va_list args;
  292. va_start(args, msg);
  293. (void)vsprintf(msgline, msg, args);
  294. va_end(args);
  295. msgflag = TRUE;
  296. }