editcmd.c 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853
  1. /* editor high level editing commands.
  2. Copyright (C) 1996, 1997 the Free Software Foundation
  3. Authors: 1996, 1997 Paul Sheer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307, USA.
  16. */
  17. /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
  18. #include <config.h>
  19. #include <ctype.h>
  20. #include "edit.h"
  21. #include "editlock.h"
  22. #include "editcmddef.h"
  23. #include "edit-widget.h"
  24. #include "src/color.h" /* dialog_colors */
  25. #include "src/tty.h" /* LINES */
  26. #include "src/widget.h" /* listbox_new() */
  27. #include "src/layout.h" /* clr_scr() */
  28. #include "src/main.h" /* mc_home */
  29. #include "src/help.h" /* interactive_display() */
  30. #include "src/key.h" /* XCTRL */
  31. #include "src/dialog.h" /* do_refresh() */
  32. #include "src/wtools.h" /* message() */
  33. #include "src/charsets.h"
  34. #define edit_get_load_file(f,h) input_dialog (h, _(" Enter file name: "), f)
  35. #define edit_get_save_file(f,h) input_dialog (h, _(" Enter file name: "), f)
  36. /* globals: */
  37. /* search and replace: */
  38. int replace_scanf = 0;
  39. int replace_regexp = 0;
  40. int replace_all = 0;
  41. int replace_prompt = 1;
  42. int replace_whole = 0;
  43. int replace_case = 0;
  44. int replace_backwards = 0;
  45. int search_create_bookmark = 0;
  46. /* queries on a save */
  47. int edit_confirm_save = 1;
  48. #define NUM_REPL_ARGS 64
  49. #define MAX_REPL_LEN 1024
  50. static inline int my_lower_case (int c)
  51. {
  52. return tolower(c & 0xFF);
  53. }
  54. char *strcasechr (const unsigned char *s, int c)
  55. {
  56. for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s)
  57. if (*s == '\0')
  58. return 0;
  59. return (char *) s;
  60. }
  61. #ifndef HAVE_MEMMOVE
  62. /* for Christophe */
  63. static void *memmove (void *dest, const void *src, size_t n)
  64. {
  65. char *t, *s;
  66. if (dest <= src) {
  67. t = (char *) dest;
  68. s = (char *) src;
  69. while (n--)
  70. *t++ = *s++;
  71. } else {
  72. t = (char *) dest + n;
  73. s = (char *) src + n;
  74. while (n--)
  75. *--t = *--s;
  76. }
  77. return dest;
  78. }
  79. #endif /* !HAVE_MEMMOVE */
  80. /* #define itoa MY_itoa <---- this line is now in edit.h */
  81. static char *
  82. MY_itoa (int i)
  83. {
  84. static char t[14];
  85. char *s = t + 13;
  86. int j = i;
  87. *s-- = 0;
  88. do {
  89. *s-- = i % 10 + '0';
  90. } while ((i = i / 10));
  91. if (j < 0)
  92. *s-- = '-';
  93. return ++s;
  94. }
  95. /* Temporary strings */
  96. static char *stacked[16];
  97. /*
  98. This joins strings end on end and allocates memory for the result.
  99. The result is later automatically free'd and must not be free'd
  100. by the caller.
  101. */
  102. char *catstrs (const char *first,...)
  103. {
  104. static int i = 0;
  105. va_list ap;
  106. int len;
  107. char *data;
  108. if (!first)
  109. return 0;
  110. len = strlen (first);
  111. va_start (ap, first);
  112. while ((data = va_arg (ap, char *)) != 0)
  113. len += strlen (data);
  114. len++;
  115. i = (i + 1) % 16;
  116. g_free (stacked[i]);
  117. stacked[i] = g_malloc (len);
  118. va_end (ap);
  119. va_start (ap, first);
  120. strcpy (stacked[i], first);
  121. while ((data = va_arg (ap, char *)) != 0)
  122. strcat (stacked[i], data);
  123. va_end (ap);
  124. return stacked[i];
  125. }
  126. /* Free temporary strings */
  127. void freestrs(void)
  128. {
  129. int i;
  130. for (i = 0; i < sizeof(stacked) / sizeof(stacked[0]); i++) {
  131. g_free (stacked[i]);
  132. stacked[i] = NULL;
  133. }
  134. }
  135. void edit_help_cmd (WEdit * edit)
  136. {
  137. interactive_display (NULL, "[Internal File Editor]");
  138. edit->force |= REDRAW_COMPLETELY;
  139. }
  140. void edit_refresh_cmd (WEdit * edit)
  141. {
  142. #ifndef HAVE_SLANG
  143. clr_scr();
  144. do_refresh();
  145. #else
  146. {
  147. int color;
  148. edit_get_syntax_color (edit, -1, &color);
  149. }
  150. touchwin(stdscr);
  151. #endif /* !HAVE_SLANG */
  152. mc_refresh();
  153. doupdate();
  154. }
  155. /* If 0 (quick save) then a) create/truncate <filename> file,
  156. b) save to <filename>;
  157. if 1 (safe save) then a) save to <tempnam>,
  158. b) rename <tempnam> to <filename>;
  159. if 2 (do backups) then a) save to <tempnam>,
  160. b) rename <filename> to <filename.backup_ext>,
  161. c) rename <tempnam> to <filename>. */
  162. /* returns 0 on error */
  163. int
  164. edit_save_file (WEdit *edit, const char *filename)
  165. {
  166. char *p;
  167. long filelen = 0;
  168. char *savename = 0;
  169. int this_save_mode, fd;
  170. if (!filename)
  171. return 0;
  172. if (!*filename)
  173. return 0;
  174. if (*filename != PATH_SEP && edit->dir) {
  175. savename = concat_dir_and_file (edit->dir, filename);
  176. filename = catstrs (savename, NULL);
  177. g_free (savename);
  178. }
  179. if (!vfs_file_is_local (filename) ||
  180. (fd = mc_open (filename, O_WRONLY | O_BINARY)) == -1) {
  181. /*
  182. * The file does not exists yet, so no safe save or
  183. * backup are necessary.
  184. */
  185. this_save_mode = EDIT_QUICK_SAVE;
  186. } else {
  187. mc_close (fd);
  188. this_save_mode = option_save_mode;
  189. }
  190. if (this_save_mode != EDIT_QUICK_SAVE) {
  191. char *savedir, *slashpos, *saveprefix;
  192. slashpos = strrchr (filename, PATH_SEP);
  193. if (slashpos) {
  194. savedir = g_strdup (filename);
  195. savedir[slashpos - filename + 1] = '\0';
  196. } else
  197. savedir = g_strdup (".");
  198. saveprefix = concat_dir_and_file (savedir, "cooledit");
  199. g_free (savedir);
  200. fd = mc_mkstemps (&savename, saveprefix, NULL);
  201. g_free (saveprefix);
  202. if (!savename)
  203. return 0;
  204. /* FIXME:
  205. * Close for now because mc_mkstemps use pure open system call
  206. * to create temporary file and it needs to be reopened by
  207. * VFS-aware mc_open().
  208. */
  209. close (fd);
  210. } else
  211. savename = g_strdup (filename);
  212. mc_chown (savename, edit->stat1.st_uid, edit->stat1.st_gid);
  213. mc_chmod (savename, edit->stat1.st_mode);
  214. if ((fd =
  215. mc_open (savename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
  216. edit->stat1.st_mode)) == -1)
  217. goto error_save;
  218. /* pipe save */
  219. if ((p = edit_get_write_filter (savename, filename))) {
  220. FILE *file;
  221. mc_close (fd);
  222. file = (FILE *) popen (p, "w");
  223. if (file) {
  224. filelen = edit_write_stream (edit, file);
  225. #if 1
  226. pclose (file);
  227. #else
  228. if (pclose (file) != 0) {
  229. edit_error_dialog (_("Error"),
  230. catstrs (_(" Error writing to pipe: "),
  231. p, " ", 0));
  232. g_free (p);
  233. goto error_save;
  234. }
  235. #endif
  236. } else {
  237. edit_error_dialog (_("Error"),
  238. get_sys_error (catstrs
  239. (_
  240. (" Cannot open pipe for writing: "),
  241. p, " ", 0)));
  242. g_free (p);
  243. goto error_save;
  244. }
  245. g_free (p);
  246. } else {
  247. long buf;
  248. buf = 0;
  249. filelen = edit->last_byte;
  250. while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
  251. if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE)
  252. != EDIT_BUF_SIZE) {
  253. mc_close (fd);
  254. goto error_save;
  255. }
  256. buf++;
  257. }
  258. if (mc_write
  259. (fd, (char *) edit->buffers1[buf],
  260. edit->curs1 & M_EDIT_BUF_SIZE) !=
  261. (edit->curs1 & M_EDIT_BUF_SIZE)) {
  262. filelen = -1;
  263. } else if (edit->curs2) {
  264. edit->curs2--;
  265. buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
  266. if (mc_write
  267. (fd,
  268. (char *) edit->buffers2[buf] + EDIT_BUF_SIZE -
  269. (edit->curs2 & M_EDIT_BUF_SIZE) - 1,
  270. 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) !=
  271. 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) {
  272. filelen = -1;
  273. } else {
  274. while (--buf >= 0) {
  275. if (mc_write
  276. (fd, (char *) edit->buffers2[buf],
  277. EDIT_BUF_SIZE) != EDIT_BUF_SIZE) {
  278. filelen = -1;
  279. break;
  280. }
  281. }
  282. }
  283. edit->curs2++;
  284. }
  285. if (mc_close (fd))
  286. goto error_save;
  287. }
  288. if (filelen != edit->last_byte)
  289. goto error_save;
  290. if (this_save_mode == EDIT_DO_BACKUP)
  291. if (mc_rename (filename, catstrs (filename, option_backup_ext, 0))
  292. == -1)
  293. goto error_save;
  294. if (this_save_mode != EDIT_QUICK_SAVE)
  295. if (mc_rename (savename, filename) == -1)
  296. goto error_save;
  297. g_free (savename);
  298. return 1;
  299. error_save:
  300. /* FIXME: Is this safe ?
  301. * if (this_save_mode != EDIT_QUICK_SAVE)
  302. * mc_unlink (savename);
  303. */
  304. g_free (savename);
  305. return 0;
  306. }
  307. /*
  308. I changed this from Oleg's original routine so
  309. that option_backup_ext works with coolwidgets as well. This
  310. does mean there is a memory leak - paul.
  311. */
  312. void menu_save_mode_cmd (void)
  313. {
  314. #define DLG_X 38
  315. #define DLG_Y 10
  316. static char *str_result;
  317. static int save_mode_new;
  318. static char *str[] =
  319. {
  320. N_("Quick save "),
  321. N_("Safe save "),
  322. N_("Do backups -->")};
  323. static QuickWidget widgets[] =
  324. {
  325. {quick_button, 18, DLG_X, 7, DLG_Y, N_("&Cancel"), 0,
  326. B_CANCEL, 0, 0, "c"},
  327. {quick_button, 6, DLG_X, 7, DLG_Y, N_("&OK"), 0,
  328. B_ENTER, 0, 0, "o"},
  329. {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
  330. 0, 0, &str_result, "edit-backup-ext"},
  331. {quick_label, 22, DLG_X, 4, DLG_Y, N_("Extension:"), 0,
  332. 0, 0, 0, "savemext"},
  333. {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
  334. 0, &save_mode_new, str, "t"},
  335. {0}};
  336. static QuickDialog dialog =
  337. {DLG_X, DLG_Y, -1, -1, N_(" Edit Save Mode "), "[Edit Save Mode]",
  338. widgets};
  339. static int i18n_flag = 0;
  340. if (!i18n_flag) {
  341. int i;
  342. int maxlen = 0;
  343. int dlg_x;
  344. int l1;
  345. /* OK/Cancel buttons */
  346. l1 = strlen (_(widgets[0].text)) + strlen (_(widgets[1].text)) + 5;
  347. maxlen = max (maxlen, l1);
  348. for (i = 0; i < 3; i++ ) {
  349. str[i] = _(str[i]);
  350. maxlen = max (maxlen, strlen (str[i]) + 7);
  351. }
  352. i18n_flag = 1;
  353. dlg_x = maxlen + strlen (_(widgets[3].text)) + 5 + 1;
  354. widgets[2].hotkey_pos = strlen (_(widgets[3].text)); /* input field length */
  355. dlg_x = min (COLS, dlg_x);
  356. dialog.xlen = dlg_x;
  357. i = (dlg_x - l1)/3;
  358. widgets[1].relative_x = i;
  359. widgets[0].relative_x = i + strlen (_(widgets[1].text)) + i + 4;
  360. widgets[2].relative_x = widgets[3].relative_x = maxlen + 2;
  361. for (i = 0; i < sizeof (widgets)/sizeof (widgets[0]); i++)
  362. widgets[i].x_divisions = dlg_x;
  363. }
  364. widgets[2].text = option_backup_ext;
  365. widgets[4].value = option_save_mode;
  366. if (quick_dialog (&dialog) != B_ENTER)
  367. return;
  368. option_save_mode = save_mode_new;
  369. option_backup_ext = str_result; /* this is a memory leak */
  370. option_backup_ext_int = 0;
  371. str_result[min (strlen (str_result), sizeof (int))] = '\0';
  372. memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
  373. }
  374. void
  375. edit_set_filename (WEdit *edit, const char *f)
  376. {
  377. if (edit->filename)
  378. g_free (edit->filename);
  379. if (!f)
  380. f = "";
  381. edit->filename = g_strdup (f);
  382. if (edit->dir == NULL && *f != PATH_SEP)
  383. #ifdef USE_VFS
  384. edit->dir = g_strdup (vfs_get_current_dir ());
  385. #else
  386. edit->dir = g_get_current_dir ();
  387. #endif
  388. }
  389. /* Here we want to warn the users of overwriting an existing file,
  390. but only if they have made a change to the filename */
  391. /* returns 1 on success */
  392. int
  393. edit_save_as_cmd (WEdit *edit)
  394. {
  395. /* This heads the 'Save As' dialog box */
  396. char *exp;
  397. int save_lock = 0;
  398. int different_filename = 0;
  399. exp = edit_get_save_file (edit->filename, _(" Save As "));
  400. edit_push_action (edit, KEY_PRESS + edit->start_display);
  401. if (exp) {
  402. if (!*exp) {
  403. g_free (exp);
  404. edit->force |= REDRAW_COMPLETELY;
  405. return 0;
  406. } else {
  407. if (strcmp (edit->filename, exp)) {
  408. int file;
  409. different_filename = 1;
  410. if ((file = mc_open (exp, O_RDONLY | O_BINARY)) != -1) {
  411. /* the file exists */
  412. mc_close (file);
  413. /* Overwrite the current file or cancel the operation */
  414. if (edit_query_dialog2
  415. (_("Warning"),
  416. _(" A file already exists with this name. "),
  417. _("Overwrite"), _("Cancel"))) {
  418. edit->force |= REDRAW_COMPLETELY;
  419. g_free (exp);
  420. return 0;
  421. }
  422. }
  423. save_lock = edit_lock_file (exp);
  424. } else {
  425. /* filenames equal, check if already locked */
  426. if (!edit->locked && !edit->delete_file)
  427. save_lock = edit_lock_file (exp);
  428. }
  429. if (edit_save_file (edit, exp)) {
  430. /* Succesful, so unlock both files */
  431. if (strcmp (edit->filename, exp)) {
  432. if (save_lock)
  433. edit_unlock_file (exp);
  434. if (edit->locked)
  435. edit->locked = edit_unlock_file (edit->filename);
  436. } else {
  437. if (edit->locked || save_lock)
  438. edit->locked = edit_unlock_file (edit->filename);
  439. }
  440. edit_set_filename (edit, exp);
  441. g_free (exp);
  442. edit->modified = 0;
  443. edit->delete_file = 0;
  444. if (different_filename)
  445. edit_load_syntax (edit, 0, 0);
  446. edit->force |= REDRAW_COMPLETELY;
  447. return 1;
  448. } else {
  449. /* Failed, so maintain modify (not save) lock */
  450. if (strcmp (edit->filename, exp) && save_lock)
  451. edit_unlock_file (exp);
  452. if (save_lock)
  453. edit->locked = edit_unlock_file (edit->filename);
  454. g_free (exp);
  455. edit_error_dialog (_(" Save As "),
  456. get_sys_error (_
  457. (" Cannot save file. ")));
  458. edit->force |= REDRAW_COMPLETELY;
  459. return 0;
  460. }
  461. }
  462. }
  463. edit->force |= REDRAW_COMPLETELY;
  464. return 0;
  465. }
  466. /* {{{ Macro stuff starts here */
  467. static int
  468. raw_callback (struct Dlg_head *h, int key, int Msg)
  469. {
  470. switch (Msg) {
  471. case DLG_KEY:
  472. h->running = 0;
  473. h->ret_value = key;
  474. return MSG_HANDLED;
  475. }
  476. return default_dlg_callback (h, key, Msg);;
  477. }
  478. /* gets a raw key from the keyboard. Passing cancel = 1 draws
  479. a cancel button thus allowing c-c etc. Alternatively, cancel = 0
  480. will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
  481. and Esc are cannot returned */
  482. int
  483. edit_raw_key_query (char *heading, char *query, int cancel)
  484. {
  485. int w = strlen (query) + 7;
  486. struct Dlg_head *raw_dlg =
  487. create_dlg (0, 0, 7, w, dialog_colors, raw_callback,
  488. NULL, heading,
  489. DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
  490. if (cancel)
  491. add_widget (raw_dlg,
  492. button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON,
  493. _("Cancel"), 0));
  494. add_widget (raw_dlg, label_new (3 - cancel, 2, query));
  495. add_widget (raw_dlg,
  496. input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
  497. run_dlg (raw_dlg);
  498. w = raw_dlg->ret_value;
  499. destroy_dlg (raw_dlg);
  500. if (cancel) {
  501. if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR
  502. || w == B_CANCEL)
  503. return 0;
  504. }
  505. return w;
  506. }
  507. /* creates a macro file if it doesn't exist */
  508. static FILE *edit_open_macro_file (const char *r)
  509. {
  510. char *filename;
  511. int file;
  512. filename = catstrs (home_dir, MACRO_FILE, 0);
  513. if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
  514. return 0;
  515. close (file);
  516. return fopen (filename, r);
  517. }
  518. #define MAX_MACROS 1024
  519. static int saved_macro[MAX_MACROS + 1];
  520. static int saved_macros_loaded = 0;
  521. /*
  522. This is just to stop the macro file be loaded over and over for keys
  523. that aren't defined to anything. On slow systems this could be annoying.
  524. */
  525. static int
  526. macro_exists (int k)
  527. {
  528. int i;
  529. for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
  530. if (saved_macro[i] == k)
  531. return i;
  532. return -1;
  533. }
  534. /* returns 1 on error */
  535. static int
  536. edit_delete_macro (WEdit * edit, int k)
  537. {
  538. struct macro macro[MAX_MACRO_LENGTH];
  539. FILE *f, *g;
  540. int s, i, n, j = 0;
  541. if (saved_macros_loaded)
  542. if ((j = macro_exists (k)) < 0)
  543. return 0;
  544. g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
  545. if (!g) {
  546. /* This heads the delete macro error dialog box */
  547. edit_error_dialog (_(" Delete macro "),
  548. /* 'Open' = load temp file */
  549. get_sys_error (_(" Cannot open temp file ")));
  550. return 1;
  551. }
  552. f = edit_open_macro_file ("r");
  553. if (!f) {
  554. /* This heads the delete macro error dialog box */
  555. edit_error_dialog (_(" Delete macro "),
  556. /* 'Open' = load temp file */
  557. get_sys_error (_(" Cannot open macro file ")));
  558. fclose (g);
  559. return 1;
  560. }
  561. for (;;) {
  562. n = fscanf (f, ("key '%d 0': "), &s);
  563. if (!n || n == EOF)
  564. break;
  565. n = 0;
  566. while (fscanf (f, "%hd %hd, ", &macro[n].command, &macro[n].ch))
  567. n++;
  568. fscanf (f, ";\n");
  569. if (s != k) {
  570. fprintf (g, ("key '%d 0': "), s);
  571. for (i = 0; i < n; i++)
  572. fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
  573. fprintf (g, ";\n");
  574. }
  575. }
  576. fclose (f);
  577. fclose (g);
  578. if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
  579. /* This heads the delete macro error dialog box */
  580. edit_error_dialog (_(" Delete macro "),
  581. get_sys_error (_(" Cannot overwrite macro file ")));
  582. return 1;
  583. }
  584. if (saved_macros_loaded)
  585. memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
  586. return 0;
  587. }
  588. /* returns 0 on error */
  589. int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
  590. {
  591. FILE *f;
  592. int s, i;
  593. edit_push_action (edit, KEY_PRESS + edit->start_display);
  594. /* This heads the 'Macro' dialog box */
  595. s = edit_raw_key_query (_(" Save macro "),
  596. /* Input line for a single key press follows the ':' */
  597. _(" Press the macro's new hotkey: "), 1);
  598. edit->force |= REDRAW_COMPLETELY;
  599. if (s) {
  600. if (edit_delete_macro (edit, s))
  601. return 0;
  602. f = edit_open_macro_file ("a+");
  603. if (f) {
  604. fprintf (f, ("key '%d 0': "), s);
  605. for (i = 0; i < n; i++)
  606. fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
  607. fprintf (f, ";\n");
  608. fclose (f);
  609. if (saved_macros_loaded) {
  610. for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
  611. saved_macro[i] = s;
  612. }
  613. return 1;
  614. } else
  615. /* This heads the 'Save Macro' dialog box */
  616. edit_error_dialog (_(" Save macro "), get_sys_error (_(" Cannot open macro file ")));
  617. }
  618. return 0;
  619. }
  620. void edit_delete_macro_cmd (WEdit * edit)
  621. {
  622. int command;
  623. command = edit_raw_key_query (_ (" Delete macro "),
  624. _ (" Press macro hotkey: "), 1);
  625. if (!command)
  626. return;
  627. edit_delete_macro (edit, command);
  628. }
  629. /* return 0 on error */
  630. int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
  631. {
  632. FILE *f;
  633. int s, i = 0, found = 0;
  634. if (saved_macros_loaded)
  635. if (macro_exists (k) < 0)
  636. return 0;
  637. if ((f = edit_open_macro_file ("r"))) {
  638. struct macro dummy;
  639. do {
  640. int u;
  641. u = fscanf (f, ("key '%d 0': "), &s);
  642. if (!u || u == EOF)
  643. break;
  644. if (!saved_macros_loaded)
  645. saved_macro[i++] = s;
  646. if (!found) {
  647. *n = 0;
  648. while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", &macro[*n].command, &macro[*n].ch))
  649. (*n)++;
  650. } else {
  651. while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
  652. }
  653. fscanf (f, ";\n");
  654. if (s == k)
  655. found = 1;
  656. } while (!found || !saved_macros_loaded);
  657. if (!saved_macros_loaded) {
  658. saved_macro[i] = 0;
  659. saved_macros_loaded = 1;
  660. }
  661. fclose (f);
  662. return found;
  663. } else
  664. /* This heads the 'Load Macro' dialog box */
  665. edit_error_dialog (_(" Load macro "),
  666. get_sys_error (_(" Cannot open macro file ")));
  667. return 0;
  668. }
  669. /* }}} Macro stuff starts here */
  670. /* returns 1 on success */
  671. int edit_save_confirm_cmd (WEdit * edit)
  672. {
  673. char *f;
  674. if (edit_confirm_save) {
  675. f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
  676. /* Buttons to 'Confirm save file' query */
  677. if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
  678. return 0;
  679. }
  680. return edit_save_cmd (edit);
  681. }
  682. /* returns 1 on success */
  683. int edit_save_cmd (WEdit * edit)
  684. {
  685. int res, save_lock = 0;
  686. if (!edit->locked && !edit->delete_file)
  687. save_lock = edit_lock_file (edit->filename);
  688. res = edit_save_file (edit, edit->filename);
  689. /* Maintain modify (not save) lock on failure */
  690. if ((res && edit->locked) || save_lock)
  691. edit->locked = edit_unlock_file (edit->filename);
  692. /* On failure try 'save as', it does locking on its own */
  693. if (!res)
  694. return edit_save_as_cmd (edit);
  695. edit->force |= REDRAW_COMPLETELY;
  696. edit->delete_file = 0;
  697. edit->modified = 0;
  698. return 1;
  699. }
  700. /* returns 1 on success */
  701. int edit_new_cmd (WEdit * edit)
  702. {
  703. if (edit->modified) {
  704. if (edit_query_dialog2 (_ ("Warning"), _ (" Current text was modified without a file save. \n Continue discards these changes. "), _ ("Continue"), _ ("Cancel"))) {
  705. edit->force |= REDRAW_COMPLETELY;
  706. return 0;
  707. }
  708. }
  709. edit->force |= REDRAW_COMPLETELY;
  710. if (edit->locked)
  711. edit->locked = edit_unlock_file (edit->filename);
  712. return edit_renew (edit); /* if this gives an error, something has really screwed up */
  713. }
  714. /* returns 1 on error */
  715. static int
  716. edit_load_file_from_filename (WEdit * edit, char *exp)
  717. {
  718. int prev_locked = edit->locked;
  719. char *prev_filename = g_strdup (edit->filename);
  720. if (!edit_reload (edit, exp)) {
  721. g_free (prev_filename);
  722. return 1;
  723. }
  724. if (prev_locked)
  725. edit_unlock_file (prev_filename);
  726. g_free (prev_filename);
  727. return 0;
  728. }
  729. int
  730. edit_load_cmd (WEdit *edit)
  731. {
  732. char *exp;
  733. if (edit->modified) {
  734. if (edit_query_dialog2
  735. (_("Warning"),
  736. _(" Current text was modified without a file save. \n"
  737. " Continue discards these changes. "), _("Continue"),
  738. _("Cancel"))) {
  739. edit->force |= REDRAW_COMPLETELY;
  740. return 0;
  741. }
  742. }
  743. exp = edit_get_load_file (edit->filename, _(" Load "));
  744. if (exp) {
  745. if (*exp)
  746. edit_load_file_from_filename (edit, exp);
  747. g_free (exp);
  748. }
  749. edit->force |= REDRAW_COMPLETELY;
  750. return 0;
  751. }
  752. /*
  753. if mark2 is -1 then marking is from mark1 to the cursor.
  754. Otherwise its between the markers. This handles this.
  755. Returns 1 if no text is marked.
  756. */
  757. int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
  758. {
  759. if (edit->mark1 != edit->mark2) {
  760. if (edit->mark2 >= 0) {
  761. *start_mark = min (edit->mark1, edit->mark2);
  762. *end_mark = max (edit->mark1, edit->mark2);
  763. } else {
  764. *start_mark = min (edit->mark1, edit->curs1);
  765. *end_mark = max (edit->mark1, edit->curs1);
  766. edit->column2 = edit->curs_col;
  767. }
  768. return 0;
  769. } else {
  770. *start_mark = *end_mark = 0;
  771. edit->column2 = edit->column1 = 0;
  772. return 1;
  773. }
  774. }
  775. #define space_width 1
  776. static void
  777. edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
  778. {
  779. long cursor;
  780. int i, col;
  781. cursor = edit->curs1;
  782. col = edit_get_col (edit);
  783. for (i = 0; i < size; i++) {
  784. if (data[i] == '\n') { /* fill in and move to next line */
  785. int l;
  786. long p;
  787. if (edit_get_byte (edit, edit->curs1) != '\n') {
  788. l = width - (edit_get_col (edit) - col);
  789. while (l > 0) {
  790. edit_insert (edit, ' ');
  791. l -= space_width;
  792. }
  793. }
  794. for (p = edit->curs1;; p++) {
  795. if (p == edit->last_byte) {
  796. edit_cursor_move (edit, edit->last_byte - edit->curs1);
  797. edit_insert_ahead (edit, '\n');
  798. p++;
  799. break;
  800. }
  801. if (edit_get_byte (edit, p) == '\n') {
  802. p++;
  803. break;
  804. }
  805. }
  806. edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
  807. l = col - edit_get_col (edit);
  808. while (l >= space_width) {
  809. edit_insert (edit, ' ');
  810. l -= space_width;
  811. }
  812. continue;
  813. }
  814. edit_insert (edit, data[i]);
  815. }
  816. edit_cursor_move (edit, cursor - edit->curs1);
  817. }
  818. void
  819. edit_block_copy_cmd (WEdit *edit)
  820. {
  821. long start_mark, end_mark, current = edit->curs1;
  822. int size, x;
  823. unsigned char *copy_buf;
  824. edit_update_curs_col (edit);
  825. x = edit->curs_col;
  826. if (eval_marks (edit, &start_mark, &end_mark))
  827. return;
  828. if (column_highlighting)
  829. if ((x >= edit->column1 && x < edit->column2)
  830. || (x > edit->column2 && x <= edit->column1))
  831. return;
  832. copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
  833. /* all that gets pushed are deletes hence little space is used on the stack */
  834. edit_push_markers (edit);
  835. if (column_highlighting) {
  836. edit_insert_column_of_text (edit, copy_buf, size,
  837. abs (edit->column2 - edit->column1));
  838. } else {
  839. while (size--)
  840. edit_insert_ahead (edit, copy_buf[size]);
  841. }
  842. g_free (copy_buf);
  843. edit_scroll_screen_over_cursor (edit);
  844. if (column_highlighting) {
  845. edit_set_markers (edit, 0, 0, 0, 0);
  846. edit_push_action (edit, COLUMN_ON);
  847. column_highlighting = 0;
  848. } else if (start_mark < current && end_mark > current)
  849. edit_set_markers (edit, start_mark,
  850. end_mark + end_mark - start_mark, 0, 0);
  851. edit->force |= REDRAW_PAGE;
  852. }
  853. void
  854. edit_block_move_cmd (WEdit *edit)
  855. {
  856. long count;
  857. long current;
  858. unsigned char *copy_buf;
  859. long start_mark, end_mark;
  860. int deleted = 0;
  861. int x = 0;
  862. if (eval_marks (edit, &start_mark, &end_mark))
  863. return;
  864. if (column_highlighting) {
  865. edit_update_curs_col (edit);
  866. x = edit->curs_col;
  867. if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
  868. if ((x > edit->column1 && x < edit->column2)
  869. || (x > edit->column2 && x < edit->column1))
  870. return;
  871. } else if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
  872. return;
  873. if ((end_mark - start_mark) > option_max_undo / 2)
  874. if (edit_query_dialog2
  875. (_("Warning"),
  876. _
  877. (" Block is large, you may not be able to undo this action. "),
  878. _("Continue"), _("Cancel")))
  879. return;
  880. edit_push_markers (edit);
  881. current = edit->curs1;
  882. if (column_highlighting) {
  883. int size, c1, c2, line;
  884. line = edit->curs_line;
  885. if (edit->mark2 < 0)
  886. edit_mark_cmd (edit, 0);
  887. c1 = min (edit->column1, edit->column2);
  888. c2 = max (edit->column1, edit->column2);
  889. copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
  890. if (x < c2) {
  891. edit_block_delete_cmd (edit);
  892. deleted = 1;
  893. }
  894. edit_move_to_line (edit, line);
  895. edit_cursor_move (edit,
  896. edit_move_forward3 (edit,
  897. edit_bol (edit, edit->curs1),
  898. x, 0) - edit->curs1);
  899. edit_insert_column_of_text (edit, copy_buf, size, c2 - c1);
  900. if (!deleted) {
  901. line = edit->curs_line;
  902. edit_update_curs_col (edit);
  903. x = edit->curs_col;
  904. edit_block_delete_cmd (edit);
  905. edit_move_to_line (edit, line);
  906. edit_cursor_move (edit,
  907. edit_move_forward3 (edit,
  908. edit_bol (edit,
  909. edit->curs1),
  910. x, 0) - edit->curs1);
  911. }
  912. edit_set_markers (edit, 0, 0, 0, 0);
  913. edit_push_action (edit, COLUMN_ON);
  914. column_highlighting = 0;
  915. } else {
  916. copy_buf = g_malloc (end_mark - start_mark);
  917. edit_cursor_move (edit, start_mark - edit->curs1);
  918. edit_scroll_screen_over_cursor (edit);
  919. count = start_mark;
  920. while (count < end_mark) {
  921. copy_buf[end_mark - count - 1] = edit_delete (edit);
  922. count++;
  923. }
  924. edit_scroll_screen_over_cursor (edit);
  925. edit_cursor_move (edit,
  926. current - edit->curs1 -
  927. (((current - edit->curs1) >
  928. 0) ? end_mark - start_mark : 0));
  929. edit_scroll_screen_over_cursor (edit);
  930. while (count-- > start_mark)
  931. edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
  932. edit_set_markers (edit, edit->curs1,
  933. edit->curs1 + end_mark - start_mark, 0, 0);
  934. }
  935. edit_scroll_screen_over_cursor (edit);
  936. g_free (copy_buf);
  937. edit->force |= REDRAW_PAGE;
  938. }
  939. static void
  940. edit_delete_column_of_text (WEdit * edit)
  941. {
  942. long p, q, r, m1, m2;
  943. int b, c, d;
  944. int n;
  945. eval_marks (edit, &m1, &m2);
  946. n = edit_move_forward (edit, m1, 0, m2) + 1;
  947. c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
  948. d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
  949. b = min (c, d);
  950. c = max (c, d);
  951. while (n--) {
  952. r = edit_bol (edit, edit->curs1);
  953. p = edit_move_forward3 (edit, r, b, 0);
  954. q = edit_move_forward3 (edit, r, c, 0);
  955. if (p < m1)
  956. p = m1;
  957. if (q > m2)
  958. q = m2;
  959. edit_cursor_move (edit, p - edit->curs1);
  960. while (q > p) { /* delete line between margins */
  961. if (edit_get_byte (edit, edit->curs1) != '\n')
  962. edit_delete (edit);
  963. q--;
  964. }
  965. if (n) /* move to next line except on the last delete */
  966. edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
  967. }
  968. }
  969. /* if success return 0 */
  970. int
  971. edit_block_delete (WEdit *edit)
  972. {
  973. long count;
  974. long start_mark, end_mark;
  975. if (eval_marks (edit, &start_mark, &end_mark))
  976. return 0;
  977. if (column_highlighting && edit->mark2 < 0)
  978. edit_mark_cmd (edit, 0);
  979. if ((end_mark - start_mark) > option_max_undo / 2) {
  980. /* Warning message with a query to continue or cancel the operation */
  981. if (edit_query_dialog2
  982. (_("Warning"),
  983. _
  984. (" Block is large, you may not be able to undo this action. "),
  985. _("Continue"), _("Cancel"))) {
  986. return 1;
  987. }
  988. }
  989. edit_push_markers (edit);
  990. edit_cursor_move (edit, start_mark - edit->curs1);
  991. edit_scroll_screen_over_cursor (edit);
  992. count = start_mark;
  993. if (start_mark < end_mark) {
  994. if (column_highlighting) {
  995. if (edit->mark2 < 0)
  996. edit_mark_cmd (edit, 0);
  997. edit_delete_column_of_text (edit);
  998. } else {
  999. while (count < end_mark) {
  1000. edit_delete (edit);
  1001. count++;
  1002. }
  1003. }
  1004. }
  1005. edit_set_markers (edit, 0, 0, 0, 0);
  1006. edit->force |= REDRAW_PAGE;
  1007. return 0;
  1008. }
  1009. /* returns 1 if canceelled by user */
  1010. int edit_block_delete_cmd (WEdit * edit)
  1011. {
  1012. long start_mark, end_mark;
  1013. if (eval_marks (edit, &start_mark, &end_mark)) {
  1014. edit_delete_line (edit);
  1015. return 0;
  1016. }
  1017. return edit_block_delete (edit);
  1018. }
  1019. #define INPUT_INDEX 9
  1020. #define SEARCH_DLG_WIDTH 58
  1021. #define SEARCH_DLG_HEIGHT 10
  1022. #define REPLACE_DLG_WIDTH 58
  1023. #define REPLACE_DLG_HEIGHT 15
  1024. #define CONFIRM_DLG_WIDTH 79
  1025. #define CONFIRM_DLG_HEIGTH 6
  1026. #define B_REPLACE_ALL B_USER+1
  1027. #define B_REPLACE_ONE B_USER+2
  1028. #define B_SKIP_REPLACE B_USER+3
  1029. static int
  1030. edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
  1031. {
  1032. QuickWidget quick_widgets[] =
  1033. {
  1034. {quick_button, 63, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Cancel"),
  1035. 0, B_CANCEL, 0, 0, NULL},
  1036. {quick_button, 50, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("O&ne"),
  1037. 0, B_REPLACE_ONE, 0, 0, NULL},
  1038. {quick_button, 37, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("A&ll"),
  1039. 0, B_REPLACE_ALL, 0, 0, NULL},
  1040. {quick_button, 21, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Skip"),
  1041. 0, B_SKIP_REPLACE, 0, 0, NULL},
  1042. {quick_button, 4, CONFIRM_DLG_WIDTH, 3, CONFIRM_DLG_HEIGTH, N_ ("&Replace"),
  1043. 0, B_ENTER, 0, 0, NULL},
  1044. {quick_label, 2, CONFIRM_DLG_WIDTH, 2, CONFIRM_DLG_HEIGTH, 0,
  1045. 0, 0, 0, 0, 0},
  1046. {0}};
  1047. #ifdef HAVE_CHARSET
  1048. char *msg = _(" Replace with: ");
  1049. quick_widgets[5].text = catstrs (msg, replace_text, 0);
  1050. if (*replace_text)
  1051. convert_to_display (quick_widgets[5].text + strlen (msg));
  1052. #else
  1053. quick_widgets[5].text = catstrs (_ (" Replace with: "), replace_text, 0);
  1054. #endif /* !HAVE_CHARSET */
  1055. {
  1056. QuickDialog Quick_input =
  1057. {CONFIRM_DLG_WIDTH, CONFIRM_DLG_HEIGTH, 0, 0, N_ (" Confirm replace "),
  1058. "[Input Line Keys]", 0 /*quick_widgets */ };
  1059. Quick_input.widgets = quick_widgets;
  1060. Quick_input.xpos = xpos;
  1061. /* Sometimes menu can hide replaced text. I don't like it */
  1062. if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + CONFIRM_DLG_HEIGTH - 1))
  1063. ypos -= CONFIRM_DLG_HEIGTH;
  1064. Quick_input.ypos = ypos;
  1065. return quick_dialog (&Quick_input);
  1066. }
  1067. }
  1068. static void
  1069. edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
  1070. {
  1071. int treplace_scanf = replace_scanf;
  1072. int treplace_regexp = replace_regexp;
  1073. int treplace_all = replace_all;
  1074. int treplace_prompt = replace_prompt;
  1075. int treplace_backwards = replace_backwards;
  1076. int treplace_whole = replace_whole;
  1077. int treplace_case = replace_case;
  1078. QuickWidget quick_widgets[] =
  1079. {
  1080. {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
  1081. 0, NULL},
  1082. {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
  1083. 0, NULL},
  1084. {quick_checkbox, 33, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
  1085. 0, 0, NULL},
  1086. {quick_checkbox, 33, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("replace &All"), 0, 0,
  1087. 0, 0, NULL},
  1088. {quick_checkbox, 33, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("pr&Ompt on replace"), 0, 0,
  1089. 0, 0, NULL},
  1090. {quick_checkbox, 4, REPLACE_DLG_WIDTH, 11, REPLACE_DLG_HEIGHT, N_("&Backwards"), 0, 0,
  1091. 0, 0, NULL},
  1092. {quick_checkbox, 4, REPLACE_DLG_WIDTH, 10, REPLACE_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
  1093. 0, 0, NULL},
  1094. {quick_checkbox, 4, REPLACE_DLG_WIDTH, 9, REPLACE_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
  1095. 0, 0, NULL},
  1096. {quick_checkbox, 4, REPLACE_DLG_WIDTH, 8, REPLACE_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
  1097. 0, 0, NULL},
  1098. {quick_input, 3, REPLACE_DLG_WIDTH, 7, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
  1099. 0, "edit-argord"},
  1100. {quick_label, 2, REPLACE_DLG_WIDTH, 6, REPLACE_DLG_HEIGHT, N_(" Enter replacement argument order eg. 3,2,1,4 "), 0, 0,
  1101. 0, 0, 0},
  1102. {quick_input, 3, REPLACE_DLG_WIDTH, 5, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
  1103. 0, "edit-replace"},
  1104. {quick_label, 2, REPLACE_DLG_WIDTH, 4, REPLACE_DLG_HEIGHT, N_(" Enter replacement string:"), 0, 0, 0,
  1105. 0, 0},
  1106. {quick_input, 3, REPLACE_DLG_WIDTH, 3, REPLACE_DLG_HEIGHT, "", 52, 0, 0,
  1107. 0, "edit-search"},
  1108. {quick_label, 2, REPLACE_DLG_WIDTH, 2, REPLACE_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
  1109. 0, 0},
  1110. {0}};
  1111. quick_widgets[2].result = &treplace_scanf;
  1112. quick_widgets[3].result = &treplace_all;
  1113. quick_widgets[4].result = &treplace_prompt;
  1114. quick_widgets[5].result = &treplace_backwards;
  1115. quick_widgets[6].result = &treplace_regexp;
  1116. quick_widgets[7].result = &treplace_whole;
  1117. quick_widgets[8].result = &treplace_case;
  1118. quick_widgets[9].str_result = arg_order;
  1119. quick_widgets[9].text = *arg_order;
  1120. quick_widgets[11].str_result = replace_text;
  1121. quick_widgets[11].text = *replace_text;
  1122. quick_widgets[13].str_result = search_text;
  1123. quick_widgets[13].text = *search_text;
  1124. {
  1125. QuickDialog Quick_input =
  1126. {REPLACE_DLG_WIDTH, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
  1127. "[Input Line Keys]", 0 /*quick_widgets */ };
  1128. Quick_input.widgets = quick_widgets;
  1129. if (quick_dialog (&Quick_input) != B_CANCEL) {
  1130. replace_scanf = treplace_scanf;
  1131. replace_backwards = treplace_backwards;
  1132. replace_regexp = treplace_regexp;
  1133. replace_all = treplace_all;
  1134. replace_prompt = treplace_prompt;
  1135. replace_whole = treplace_whole;
  1136. replace_case = treplace_case;
  1137. return;
  1138. } else {
  1139. *arg_order = NULL;
  1140. *replace_text = NULL;
  1141. *search_text = NULL;
  1142. return;
  1143. }
  1144. }
  1145. }
  1146. static void
  1147. edit_search_dialog (WEdit * edit, char **search_text)
  1148. {
  1149. int treplace_scanf = replace_scanf;
  1150. int treplace_regexp = replace_regexp;
  1151. int treplace_whole = replace_whole;
  1152. int treplace_case = replace_case;
  1153. int treplace_backwards = replace_backwards;
  1154. QuickWidget quick_widgets[] =
  1155. {
  1156. {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
  1157. 0, NULL},
  1158. {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
  1159. 0, NULL},
  1160. {quick_checkbox, 33, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("scanf &Expression"), 0, 0,
  1161. 0, 0, NULL },
  1162. {quick_checkbox, 33, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Backwards"), 0, 0,
  1163. 0, 0, NULL},
  1164. {quick_checkbox, 4, SEARCH_DLG_WIDTH, 6, SEARCH_DLG_HEIGHT, N_("&Regular expression"), 0, 0,
  1165. 0, 0, NULL},
  1166. {quick_checkbox, 4, SEARCH_DLG_WIDTH, 5, SEARCH_DLG_HEIGHT, N_("&Whole words only"), 0, 0,
  1167. 0, 0, NULL},
  1168. {quick_checkbox, 4, SEARCH_DLG_WIDTH, 4, SEARCH_DLG_HEIGHT, N_("case &Sensitive"), 0, 0,
  1169. 0, 0, NULL},
  1170. {quick_input, 3, SEARCH_DLG_WIDTH, 3, SEARCH_DLG_HEIGHT, "", 52, 0, 0,
  1171. 0, "edit-search"},
  1172. {quick_label, 2, SEARCH_DLG_WIDTH, 2, SEARCH_DLG_HEIGHT, N_(" Enter search string:"), 0, 0, 0,
  1173. 0, 0},
  1174. {0}};
  1175. quick_widgets[2].result = &treplace_scanf;
  1176. quick_widgets[3].result = &treplace_backwards;
  1177. quick_widgets[4].result = &treplace_regexp;
  1178. quick_widgets[5].result = &treplace_whole;
  1179. quick_widgets[6].result = &treplace_case;
  1180. quick_widgets[7].str_result = search_text;
  1181. quick_widgets[7].text = *search_text;
  1182. {
  1183. QuickDialog Quick_input =
  1184. {SEARCH_DLG_WIDTH, SEARCH_DLG_HEIGHT, -1, 0, N_("Search"),
  1185. "[Input Line Keys]", 0 /*quick_widgets */ };
  1186. Quick_input.widgets = quick_widgets;
  1187. if (quick_dialog (&Quick_input) != B_CANCEL) {
  1188. replace_scanf = treplace_scanf;
  1189. replace_backwards = treplace_backwards;
  1190. replace_regexp = treplace_regexp;
  1191. replace_whole = treplace_whole;
  1192. replace_case = treplace_case;
  1193. } else {
  1194. *search_text = NULL;
  1195. }
  1196. }
  1197. }
  1198. static long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
  1199. #define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
  1200. sargs[4], sargs[5], sargs[6], sargs[7], \
  1201. sargs[8], sargs[9], sargs[10], sargs[11], \
  1202. sargs[12], sargs[13], sargs[14], sargs[15]
  1203. #define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
  1204. sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
  1205. sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
  1206. sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
  1207. /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
  1208. /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
  1209. static int
  1210. string_regexp_search (char *pattern, char *string, int len, int match_type,
  1211. int match_bol, int icase, int *found_len, void *d)
  1212. {
  1213. static regex_t r;
  1214. static char *old_pattern = NULL;
  1215. static int old_type, old_icase;
  1216. regmatch_t *pmatch;
  1217. static regmatch_t s[1];
  1218. pmatch = (regmatch_t *) d;
  1219. if (!pmatch)
  1220. pmatch = s;
  1221. if (!old_pattern || strcmp (old_pattern, pattern)
  1222. || old_type != match_type || old_icase != icase) {
  1223. if (old_pattern) {
  1224. regfree (&r);
  1225. g_free (old_pattern);
  1226. old_pattern = 0;
  1227. }
  1228. if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
  1229. *found_len = 0;
  1230. return -3;
  1231. }
  1232. old_pattern = g_strdup (pattern);
  1233. old_type = match_type;
  1234. old_icase = icase;
  1235. }
  1236. if (regexec
  1237. (&r, string, d ? NUM_REPL_ARGS : 1, pmatch,
  1238. ((match_bol
  1239. || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
  1240. *found_len = 0;
  1241. return -1;
  1242. }
  1243. *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
  1244. return (pmatch[0].rm_so);
  1245. }
  1246. /* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
  1247. (and the above) routines to work properly - paul */
  1248. static long
  1249. edit_find_string (long start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only, void *d)
  1250. {
  1251. long p, q = 0;
  1252. long l = strlen ((char *) exp), f = 0;
  1253. int n = 0;
  1254. for (p = 0; p < l; p++) /* count conversions... */
  1255. if (exp[p] == '%')
  1256. if (exp[++p] != '%') /* ...except for "%%" */
  1257. n++;
  1258. if (replace_scanf || replace_regexp) {
  1259. int c;
  1260. unsigned char *buf;
  1261. unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
  1262. replace_scanf = (!replace_regexp); /* can't have both */
  1263. buf = mbuf;
  1264. if (replace_scanf) {
  1265. unsigned char e[MAX_REPL_LEN];
  1266. if (n >= NUM_REPL_ARGS)
  1267. return -3;
  1268. if (replace_case) {
  1269. for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
  1270. buf[p - start] = (*get_byte) (data, p);
  1271. } else {
  1272. for (p = 0; exp[p] != 0; p++)
  1273. exp[p] = my_lower_case (exp[p]);
  1274. for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
  1275. c = (*get_byte) (data, p);
  1276. buf[p - start] = my_lower_case (c);
  1277. }
  1278. }
  1279. buf[(q = p - start)] = 0;
  1280. strcpy ((char *) e, (char *) exp);
  1281. strcat ((char *) e, "%n");
  1282. exp = e;
  1283. while (q) {
  1284. *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
  1285. if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
  1286. if (*((int *) sargs[n])) {
  1287. *len = *((int *) sargs[n]);
  1288. return start;
  1289. }
  1290. }
  1291. if (once_only)
  1292. return -2;
  1293. if (q + start < last_byte) {
  1294. if (replace_case) {
  1295. buf[q] = (*get_byte) (data, q + start);
  1296. } else {
  1297. c = (*get_byte) (data, q + start);
  1298. buf[q] = my_lower_case (c);
  1299. }
  1300. q++;
  1301. }
  1302. buf[q] = 0;
  1303. start++;
  1304. buf++; /* move the window along */
  1305. if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
  1306. memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
  1307. buf = mbuf;
  1308. }
  1309. q--;
  1310. }
  1311. } else { /* regexp matching */
  1312. long offset = 0;
  1313. int found_start, match_bol, move_win = 0;
  1314. while (start + offset < last_byte) {
  1315. match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
  1316. if (!move_win) {
  1317. p = start + offset;
  1318. q = 0;
  1319. }
  1320. for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
  1321. mbuf[q] = (*get_byte) (data, p);
  1322. if (mbuf[q] == '\n')
  1323. break;
  1324. }
  1325. q++;
  1326. offset += q;
  1327. mbuf[q] = 0;
  1328. buf = mbuf;
  1329. while (q) {
  1330. found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len, d);
  1331. if (found_start <= -2) { /* regcomp/regexec error */
  1332. *len = 0;
  1333. return -3;
  1334. }
  1335. else if (found_start == -1) /* not found: try next line */
  1336. break;
  1337. else if (*len == 0) { /* null pattern: try again at next character */
  1338. q--;
  1339. buf++;
  1340. match_bol = 0;
  1341. continue;
  1342. }
  1343. else /* found */
  1344. return (start + offset - q + found_start);
  1345. }
  1346. if (once_only)
  1347. return -2;
  1348. if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
  1349. buf = mbuf + MAX_REPL_LEN / 2;
  1350. q = strlen ((char *) buf);
  1351. memmove (mbuf, buf, q);
  1352. p = start + q;
  1353. move_win = 1;
  1354. }
  1355. else
  1356. move_win = 0;
  1357. }
  1358. }
  1359. } else {
  1360. *len = strlen ((char *) exp);
  1361. if (replace_case) {
  1362. for (p = start; p <= last_byte - l; p++) {
  1363. if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
  1364. for (f = 0, q = 0; q < l && f < 1; q++)
  1365. if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
  1366. f = 1;
  1367. if (f == 0)
  1368. return p;
  1369. }
  1370. if (once_only)
  1371. return -2;
  1372. }
  1373. } else {
  1374. for (p = 0; exp[p] != 0; p++)
  1375. exp[p] = my_lower_case (exp[p]);
  1376. for (p = start; p <= last_byte - l; p++) {
  1377. if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
  1378. for (f = 0, q = 0; q < l && f < 1; q++)
  1379. if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
  1380. f = 1;
  1381. if (f == 0)
  1382. return p;
  1383. }
  1384. if (once_only)
  1385. return -2;
  1386. }
  1387. }
  1388. }
  1389. return -2;
  1390. }
  1391. static long
  1392. edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only, void *d)
  1393. { /*front end to find_string to check for
  1394. whole words */
  1395. long p;
  1396. p = search_start;
  1397. while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) {
  1398. if (replace_whole) {
  1399. /*If the bordering chars are not in option_whole_chars_search then word is whole */
  1400. if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
  1401. && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
  1402. return p;
  1403. if (once_only)
  1404. return -2;
  1405. } else
  1406. return p;
  1407. if (once_only)
  1408. break;
  1409. p++; /*not a whole word so continue search. */
  1410. }
  1411. return p;
  1412. }
  1413. static long
  1414. edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, void *d)
  1415. {
  1416. long p;
  1417. if (replace_backwards) {
  1418. while (search_start >= 0) {
  1419. p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1, d);
  1420. if (p == search_start)
  1421. return p;
  1422. search_start--;
  1423. }
  1424. } else {
  1425. return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0, d);
  1426. }
  1427. return -2;
  1428. }
  1429. #define is_digit(x) ((x) >= '0' && (x) <= '9')
  1430. #define snprintf(v) { \
  1431. *p1++ = *p++; \
  1432. *p1++ = '%'; \
  1433. *p1++ = 'n'; \
  1434. *p1 = '\0'; \
  1435. sprintf(s,q1,v,&n); \
  1436. s += n; \
  1437. }
  1438. /* this function uses the sprintf command to do a vprintf */
  1439. /* it takes pointers to arguments instead of the arguments themselves */
  1440. static int sprintf_p (char *str, const char *fmt,...)
  1441. __attribute__ ((format (printf, 2, 3)));
  1442. static int sprintf_p (char *str, const char *fmt,...)
  1443. {
  1444. va_list ap;
  1445. int n;
  1446. char *q, *p, *s = str;
  1447. char q1[32];
  1448. char *p1;
  1449. va_start (ap, fmt);
  1450. p = q = (char *) fmt;
  1451. while ((p = strchr (p, '%'))) {
  1452. n = p - q;
  1453. strncpy (s, q, n); /* copy stuff between format specifiers */
  1454. s += n;
  1455. *s = 0;
  1456. q = p;
  1457. p1 = q1;
  1458. *p1++ = *p++;
  1459. if (*p == '%') {
  1460. p++;
  1461. *s++ = '%';
  1462. q = p;
  1463. continue;
  1464. }
  1465. if (*p == 'n') {
  1466. p++;
  1467. /* do nothing */
  1468. q = p;
  1469. continue;
  1470. }
  1471. if (*p == '#')
  1472. *p1++ = *p++;
  1473. if (*p == '0')
  1474. *p1++ = *p++;
  1475. if (*p == '-')
  1476. *p1++ = *p++;
  1477. if (*p == '+')
  1478. *p1++ = *p++;
  1479. if (*p == '*') {
  1480. p++;
  1481. strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */
  1482. p1 += strlen (p1);
  1483. } else {
  1484. while (is_digit (*p))
  1485. *p1++ = *p++;
  1486. }
  1487. if (*p == '.')
  1488. *p1++ = *p++;
  1489. if (*p == '*') {
  1490. p++;
  1491. strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */
  1492. p1 += strlen (p1);
  1493. } else {
  1494. while (is_digit (*p))
  1495. *p1++ = *p++;
  1496. }
  1497. /* flags done, now get argument */
  1498. if (*p == 's') {
  1499. snprintf (va_arg (ap, char *));
  1500. } else if (*p == 'h') {
  1501. if (strchr ("diouxX", *p))
  1502. snprintf (*va_arg (ap, short *));
  1503. } else if (*p == 'l') {
  1504. *p1++ = *p++;
  1505. if (strchr ("diouxX", *p))
  1506. snprintf (*va_arg (ap, long *));
  1507. } else if (strchr ("cdiouxX", *p)) {
  1508. snprintf (*va_arg (ap, int *));
  1509. } else if (*p == 'L') {
  1510. *p1++ = *p++;
  1511. if (strchr ("EefgG", *p))
  1512. snprintf (*va_arg (ap, double *)); /* should be long double */
  1513. } else if (strchr ("EefgG", *p)) {
  1514. snprintf (*va_arg (ap, double *));
  1515. } else if (strchr ("DOU", *p)) {
  1516. snprintf (*va_arg (ap, long *));
  1517. } else if (*p == 'p') {
  1518. snprintf (*va_arg (ap, void **));
  1519. }
  1520. q = p;
  1521. }
  1522. va_end (ap);
  1523. sprintf (s, q); /* print trailing leftover */
  1524. return s - str + strlen (s);
  1525. }
  1526. static void regexp_error (WEdit *edit)
  1527. {
  1528. /* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
  1529. edit_error_dialog (_("Error"), _(" Invalid regular expression, or scanf expression with to many conversions "));
  1530. }
  1531. /* call with edit = 0 before shutdown to close memory leaks */
  1532. void
  1533. edit_replace_cmd (WEdit *edit, int again)
  1534. {
  1535. static regmatch_t pmatch[NUM_REPL_ARGS];
  1536. static char *old1 = NULL;
  1537. static char *old2 = NULL;
  1538. static char *old3 = NULL;
  1539. char *exp1 = "";
  1540. char *exp2 = "";
  1541. char *exp3 = "";
  1542. int replace_yes;
  1543. int replace_continue;
  1544. int treplace_prompt = 0;
  1545. int i = 0;
  1546. long times_replaced = 0, last_search;
  1547. int argord[NUM_REPL_ARGS];
  1548. if (!edit) {
  1549. if (old1) {
  1550. g_free (old1);
  1551. old1 = 0;
  1552. }
  1553. if (old2) {
  1554. g_free (old2);
  1555. old2 = 0;
  1556. }
  1557. if (old3) {
  1558. g_free (old3);
  1559. old3 = 0;
  1560. }
  1561. return;
  1562. }
  1563. last_search = edit->last_byte;
  1564. edit->force |= REDRAW_COMPLETELY;
  1565. exp1 = old1 ? old1 : exp1;
  1566. exp2 = old2 ? old2 : exp2;
  1567. exp3 = old3 ? old3 : exp3;
  1568. if (again) {
  1569. if (!old1 || !old2)
  1570. return;
  1571. exp1 = g_strdup (old1);
  1572. exp2 = g_strdup (old2);
  1573. exp3 = g_strdup (old3);
  1574. } else {
  1575. edit_push_action (edit, KEY_PRESS + edit->start_display);
  1576. convert_to_display (exp1);
  1577. convert_to_display (exp2);
  1578. edit_replace_dialog (edit, &exp1, &exp2, &exp3);
  1579. convert_from_input (exp1);
  1580. convert_from_input (exp2);
  1581. treplace_prompt = replace_prompt;
  1582. }
  1583. if (!exp1 || !*exp1) {
  1584. edit->force = REDRAW_COMPLETELY;
  1585. g_free (exp1);
  1586. g_free (exp2);
  1587. g_free (exp3);
  1588. return;
  1589. }
  1590. g_free (old1);
  1591. g_free (old2);
  1592. g_free (old3);
  1593. old1 = g_strdup (exp1);
  1594. old2 = g_strdup (exp2);
  1595. old3 = g_strdup (exp3);
  1596. {
  1597. char *s;
  1598. int ord;
  1599. while ((s = strchr (exp3, ' ')))
  1600. memmove (s, s + 1, strlen (s));
  1601. s = exp3;
  1602. for (i = 0; i < NUM_REPL_ARGS; i++) {
  1603. if (s != (char *) 1 && *s) {
  1604. ord = atoi (s);
  1605. if ((ord > 0) && (ord < NUM_REPL_ARGS))
  1606. argord[i] = ord - 1;
  1607. else
  1608. argord[i] = i;
  1609. s = strchr (s, ',') + 1;
  1610. } else
  1611. argord[i] = i;
  1612. }
  1613. }
  1614. replace_continue = replace_all;
  1615. if (edit->found_len && edit->search_start == edit->found_start + 1
  1616. && replace_backwards)
  1617. edit->search_start--;
  1618. if (edit->found_len && edit->search_start == edit->found_start - 1
  1619. && !replace_backwards)
  1620. edit->search_start++;
  1621. do {
  1622. int len = 0;
  1623. long new_start;
  1624. new_start =
  1625. edit_find (edit->search_start, (unsigned char *) exp1, &len,
  1626. last_search, (int (*)(void *, long)) edit_get_byte,
  1627. (void *) edit, pmatch);
  1628. if (new_start == -3) {
  1629. regexp_error (edit);
  1630. break;
  1631. }
  1632. edit->search_start = new_start;
  1633. /*returns negative on not found or error in pattern */
  1634. if (edit->search_start >= 0) {
  1635. edit->found_start = edit->search_start;
  1636. i = edit->found_len = len;
  1637. edit_cursor_move (edit, edit->search_start - edit->curs1);
  1638. edit_scroll_screen_over_cursor (edit);
  1639. replace_yes = 1;
  1640. if (treplace_prompt) {
  1641. int l;
  1642. l = edit->curs_row - edit->num_widget_lines / 3;
  1643. if (l > 0)
  1644. edit_scroll_downward (edit, l);
  1645. if (l < 0)
  1646. edit_scroll_upward (edit, -l);
  1647. edit_scroll_screen_over_cursor (edit);
  1648. edit->force |= REDRAW_PAGE;
  1649. edit_render_keypress (edit);
  1650. /*so that undo stops at each query */
  1651. edit_push_key_press (edit);
  1652. switch (edit_replace_prompt (edit, exp2, /* and prompt 2/3 down */
  1653. (edit->num_widget_columns -
  1654. CONFIRM_DLG_WIDTH) / 2,
  1655. edit->num_widget_lines * 2 /
  1656. 3)) {
  1657. case B_ENTER:
  1658. break;
  1659. case B_SKIP_REPLACE:
  1660. replace_yes = 0;
  1661. break;
  1662. case B_REPLACE_ALL:
  1663. treplace_prompt = 0;
  1664. replace_continue = 1;
  1665. break;
  1666. case B_REPLACE_ONE:
  1667. replace_continue = 0;
  1668. break;
  1669. case B_CANCEL:
  1670. replace_yes = 0;
  1671. replace_continue = 0;
  1672. break;
  1673. }
  1674. }
  1675. if (replace_yes) { /* delete then insert new */
  1676. if (replace_scanf || replace_regexp) {
  1677. char repl_str[MAX_REPL_LEN + 2];
  1678. /* we need to fill in sargs just like with scanf */
  1679. if (replace_regexp) {
  1680. int k, j;
  1681. for (k = 1;
  1682. k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0;
  1683. k++) {
  1684. unsigned char *t;
  1685. t = (unsigned char *) &sargs[k - 1][0];
  1686. for (j = 0;
  1687. j < pmatch[k].rm_eo - pmatch[k].rm_so
  1688. && j < 255; j++, t++)
  1689. *t = (unsigned char) edit_get_byte (edit,
  1690. edit->
  1691. search_start
  1692. -
  1693. pmatch
  1694. [0].
  1695. rm_so +
  1696. pmatch
  1697. [k].
  1698. rm_so +
  1699. j);
  1700. *t = '\0';
  1701. }
  1702. for (; k <= NUM_REPL_ARGS; k++)
  1703. sargs[k - 1][0] = 0;
  1704. }
  1705. if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
  1706. times_replaced++;
  1707. while (i--)
  1708. edit_delete (edit);
  1709. while (repl_str[++i])
  1710. edit_insert (edit, repl_str[i]);
  1711. } else {
  1712. edit_error_dialog (_(" Replace "),
  1713. _
  1714. (" Error in replacement format string. "));
  1715. replace_continue = 0;
  1716. }
  1717. } else {
  1718. times_replaced++;
  1719. while (i--)
  1720. edit_delete (edit);
  1721. while (exp2[++i])
  1722. edit_insert (edit, exp2[i]);
  1723. }
  1724. edit->found_len = i;
  1725. }
  1726. /* so that we don't find the same string again */
  1727. if (replace_backwards) {
  1728. last_search = edit->search_start;
  1729. edit->search_start--;
  1730. } else {
  1731. edit->search_start += i;
  1732. last_search = edit->last_byte;
  1733. }
  1734. edit_scroll_screen_over_cursor (edit);
  1735. } else {
  1736. char *msg = _(" Replace ");
  1737. /* try and find from right here for next search */
  1738. edit->search_start = edit->curs1;
  1739. edit_update_curs_col (edit);
  1740. edit->force |= REDRAW_PAGE;
  1741. edit_render_keypress (edit);
  1742. if (times_replaced) {
  1743. message (0, msg, _(" %ld replacements made. "),
  1744. times_replaced);
  1745. } else
  1746. edit_message_dialog (msg, _(" Search string not found "));
  1747. replace_continue = 0;
  1748. }
  1749. } while (replace_continue);
  1750. g_free (exp1);
  1751. g_free (exp2);
  1752. g_free (exp3);
  1753. edit->force = REDRAW_COMPLETELY;
  1754. edit_scroll_screen_over_cursor (edit);
  1755. }
  1756. void edit_search_cmd (WEdit * edit, int again)
  1757. {
  1758. static char *old = NULL;
  1759. char *exp = "";
  1760. if (!edit) {
  1761. if (old) {
  1762. g_free (old);
  1763. old = 0;
  1764. }
  1765. return;
  1766. }
  1767. exp = old ? old : exp;
  1768. if (again) { /*ctrl-hotkey for search again. */
  1769. if (!old)
  1770. return;
  1771. exp = g_strdup (old);
  1772. } else {
  1773. #ifdef HAVE_CHARSET
  1774. if (exp && *exp)
  1775. convert_to_display (exp);
  1776. #endif /* HAVE_CHARSET */
  1777. edit_search_dialog (edit, &exp);
  1778. #ifdef HAVE_CHARSET
  1779. if (exp && *exp)
  1780. convert_from_input (exp);
  1781. #endif /* HAVE_CHARSET */
  1782. edit_push_action (edit, KEY_PRESS + edit->start_display);
  1783. }
  1784. if (exp) {
  1785. if (*exp) {
  1786. int len = 0;
  1787. if (old)
  1788. g_free (old);
  1789. old = g_strdup (exp);
  1790. if (search_create_bookmark) {
  1791. int found = 0, books = 0;
  1792. int l = 0, l_last = -1;
  1793. long p, q = 0;
  1794. for (;;) {
  1795. p = edit_find (q, (unsigned char *) exp, &len, edit->last_byte,
  1796. (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
  1797. if (p < 0)
  1798. break;
  1799. found++;
  1800. l += edit_count_lines (edit, q, p);
  1801. if (l != l_last) {
  1802. book_mark_insert (edit, l, BOOK_MARK_FOUND_COLOR);
  1803. books++;
  1804. }
  1805. l_last = l;
  1806. q = p + 1;
  1807. }
  1808. if (found) {
  1809. /* in response to number of bookmarks added because of string being found %d times */
  1810. message (0, _("Search"), _(" %d finds made, %d bookmarks added "), found, books);
  1811. } else {
  1812. edit_error_dialog (_ ("Search"), _ (" Search string not found "));
  1813. }
  1814. } else {
  1815. if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
  1816. edit->search_start--;
  1817. if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
  1818. edit->search_start++;
  1819. edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
  1820. (int (*)(void *, long)) edit_get_byte, (void *) edit, 0);
  1821. if (edit->search_start >= 0) {
  1822. edit->found_start = edit->search_start;
  1823. edit->found_len = len;
  1824. edit_cursor_move (edit, edit->search_start - edit->curs1);
  1825. edit_scroll_screen_over_cursor (edit);
  1826. if (replace_backwards)
  1827. edit->search_start--;
  1828. else
  1829. edit->search_start++;
  1830. } else if (edit->search_start == -3) {
  1831. edit->search_start = edit->curs1;
  1832. regexp_error (edit);
  1833. } else {
  1834. edit->search_start = edit->curs1;
  1835. edit_error_dialog (_ ("Search"), _ (" Search string not found "));
  1836. }
  1837. }
  1838. }
  1839. g_free (exp);
  1840. }
  1841. edit->force |= REDRAW_COMPLETELY;
  1842. edit_scroll_screen_over_cursor (edit);
  1843. }
  1844. /*
  1845. * Check if it's OK to close the editor. If there are unsaved changes,
  1846. * ask user. Return 1 if it's OK to exit, 0 to continue editing.
  1847. */
  1848. int
  1849. edit_ok_to_exit (WEdit *edit)
  1850. {
  1851. if (!edit->modified)
  1852. return 1;
  1853. switch (edit_query_dialog3
  1854. (_("Quit"), _(" File was modified, Save with exit? "),
  1855. _("Cancel quit"), _("&Yes"), _("&No"))) {
  1856. case 1:
  1857. edit_push_markers (edit);
  1858. edit_set_markers (edit, 0, 0, 0, 0);
  1859. if (!edit_save_cmd (edit))
  1860. return 0;
  1861. break;
  1862. case 2:
  1863. if (edit->locked)
  1864. edit->locked = edit_unlock_file (edit->filename);
  1865. break;
  1866. case 0:
  1867. case -1:
  1868. return 0;
  1869. }
  1870. return 1;
  1871. }
  1872. #define TEMP_BUF_LEN 1024
  1873. /* Return a null terminated length of text. Result must be g_free'd */
  1874. unsigned char *
  1875. edit_get_block (WEdit *edit, long start, long finish, int *l)
  1876. {
  1877. unsigned char *s, *r;
  1878. r = s = g_malloc (finish - start + 1);
  1879. if (column_highlighting) {
  1880. *l = 0;
  1881. /* copy from buffer, excluding chars that are out of the column 'margins' */
  1882. while (start < finish) {
  1883. int c, x;
  1884. x = edit_move_forward3 (edit, edit_bol (edit, start), 0,
  1885. start);
  1886. c = edit_get_byte (edit, start);
  1887. if ((x >= edit->column1 && x < edit->column2)
  1888. || (x >= edit->column2 && x < edit->column1) || c == '\n') {
  1889. *s++ = c;
  1890. (*l)++;
  1891. }
  1892. start++;
  1893. }
  1894. } else {
  1895. *l = finish - start;
  1896. while (start < finish)
  1897. *s++ = edit_get_byte (edit, start++);
  1898. }
  1899. *s = 0;
  1900. return r;
  1901. }
  1902. /* save block, returns 1 on success */
  1903. int
  1904. edit_save_block (WEdit * edit, const char *filename, long start,
  1905. long finish)
  1906. {
  1907. int len, file;
  1908. if ((file =
  1909. mc_open (filename, O_CREAT | O_WRONLY | O_TRUNC,
  1910. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY)) == -1)
  1911. return 0;
  1912. if (column_highlighting) {
  1913. unsigned char *block, *p;
  1914. int r;
  1915. p = block = edit_get_block (edit, start, finish, &len);
  1916. while (len) {
  1917. r = mc_write (file, p, len);
  1918. if (r < 0)
  1919. break;
  1920. p += r;
  1921. len -= r;
  1922. }
  1923. g_free (block);
  1924. } else {
  1925. unsigned char *buf;
  1926. int i = start, end;
  1927. len = finish - start;
  1928. buf = g_malloc (TEMP_BUF_LEN);
  1929. while (start != finish) {
  1930. end = min (finish, start + TEMP_BUF_LEN);
  1931. for (; i < end; i++)
  1932. buf[i - start] = edit_get_byte (edit, i);
  1933. len -= mc_write (file, (char *) buf, end - start);
  1934. start = end;
  1935. }
  1936. g_free (buf);
  1937. }
  1938. mc_close (file);
  1939. if (len)
  1940. return 0;
  1941. return 1;
  1942. }
  1943. /* copies a block to clipboard file */
  1944. static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
  1945. {
  1946. return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
  1947. }
  1948. void edit_paste_from_history (WEdit *edit)
  1949. {
  1950. }
  1951. int edit_copy_to_X_buf_cmd (WEdit * edit)
  1952. {
  1953. long start_mark, end_mark;
  1954. if (eval_marks (edit, &start_mark, &end_mark))
  1955. return 0;
  1956. if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
  1957. edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
  1958. return 1;
  1959. }
  1960. edit_mark_cmd (edit, 1);
  1961. return 0;
  1962. }
  1963. int edit_cut_to_X_buf_cmd (WEdit * edit)
  1964. {
  1965. long start_mark, end_mark;
  1966. if (eval_marks (edit, &start_mark, &end_mark))
  1967. return 0;
  1968. if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
  1969. edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
  1970. return 1;
  1971. }
  1972. edit_block_delete_cmd (edit);
  1973. edit_mark_cmd (edit, 1);
  1974. return 0;
  1975. }
  1976. void edit_paste_from_X_buf_cmd (WEdit * edit)
  1977. {
  1978. edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
  1979. }
  1980. /*
  1981. * Ask user for the line and go to that line.
  1982. * Negative numbers mean line from the end (i.e. -1 is the last line).
  1983. */
  1984. void
  1985. edit_goto_cmd (WEdit *edit)
  1986. {
  1987. char *f;
  1988. static long line = 0; /* line as typed, saved as default */
  1989. long l;
  1990. char *error;
  1991. char s[32];
  1992. g_snprintf (s, sizeof (s), "%ld", line);
  1993. f = input_dialog (_(" Goto line "), _(" Enter line: "), line ? s : "");
  1994. if (!f)
  1995. return;
  1996. if (!*f) {
  1997. g_free (f);
  1998. return;
  1999. }
  2000. l = strtol (f, &error, 0);
  2001. if (*error) {
  2002. g_free (f);
  2003. return;
  2004. }
  2005. line = l;
  2006. if (l < 0)
  2007. l = edit->total_lines + l + 2;
  2008. edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
  2009. edit_move_to_line (edit, l - 1);
  2010. edit->force |= REDRAW_COMPLETELY;
  2011. g_free (f);
  2012. }
  2013. /* Return 1 on success */
  2014. int
  2015. edit_save_block_cmd (WEdit *edit)
  2016. {
  2017. long start_mark, end_mark;
  2018. char *exp;
  2019. if (eval_marks (edit, &start_mark, &end_mark))
  2020. return 1;
  2021. exp =
  2022. edit_get_save_file (catstrs (home_dir, CLIP_FILE, 0),
  2023. _(" Save Block "));
  2024. edit_push_action (edit, KEY_PRESS + edit->start_display);
  2025. if (exp) {
  2026. if (!*exp) {
  2027. g_free (exp);
  2028. return 0;
  2029. } else {
  2030. if (edit_save_block (edit, exp, start_mark, end_mark)) {
  2031. g_free (exp);
  2032. edit->force |= REDRAW_COMPLETELY;
  2033. return 1;
  2034. } else {
  2035. g_free (exp);
  2036. edit_error_dialog (_(" Save Block "),
  2037. get_sys_error (_
  2038. (" Cannot save file. ")));
  2039. }
  2040. }
  2041. }
  2042. edit->force |= REDRAW_COMPLETELY;
  2043. return 0;
  2044. }
  2045. /* returns 1 on success */
  2046. int
  2047. edit_insert_file_cmd (WEdit *edit)
  2048. {
  2049. char *exp = edit_get_load_file (catstrs (home_dir, CLIP_FILE, 0),
  2050. _(" Insert File "));
  2051. edit_push_action (edit, KEY_PRESS + edit->start_display);
  2052. if (exp) {
  2053. if (!*exp) {
  2054. g_free (exp);
  2055. return 0;
  2056. } else {
  2057. if (edit_insert_file (edit, exp)) {
  2058. g_free (exp);
  2059. edit->force |= REDRAW_COMPLETELY;
  2060. return 1;
  2061. } else {
  2062. g_free (exp);
  2063. edit_error_dialog (_(" Insert File "),
  2064. get_sys_error (_
  2065. (" Cannot insert file. ")));
  2066. }
  2067. }
  2068. }
  2069. edit->force |= REDRAW_COMPLETELY;
  2070. return 0;
  2071. }
  2072. /* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
  2073. int edit_sort_cmd (WEdit * edit)
  2074. {
  2075. static char *old = 0;
  2076. char *exp;
  2077. long start_mark, end_mark;
  2078. int e;
  2079. if (eval_marks (edit, &start_mark, &end_mark)) {
  2080. edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
  2081. return 0;
  2082. }
  2083. edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
  2084. exp = old ? old : "";
  2085. exp = input_dialog (_(" Run Sort "),
  2086. _(" Enter sort options (see manpage) separated by whitespace: "), exp);
  2087. if (!exp)
  2088. return 1;
  2089. if (old)
  2090. g_free (old);
  2091. old = exp;
  2092. e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
  2093. if (e) {
  2094. if (e == -1 || e == 127) {
  2095. edit_error_dialog (_(" Sort "),
  2096. get_sys_error (_(" Cannot execute sort command ")));
  2097. } else {
  2098. char q[8];
  2099. sprintf (q, "%d ", e);
  2100. edit_error_dialog (_(" Sort "),
  2101. catstrs (_(" Sort returned non-zero: "), q, 0));
  2102. }
  2103. return -1;
  2104. }
  2105. edit->force |= REDRAW_COMPLETELY;
  2106. if (edit_block_delete_cmd (edit))
  2107. return 1;
  2108. edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
  2109. return 0;
  2110. }
  2111. /*
  2112. * Ask user for a command, execute it and paste its output back to the
  2113. * editor.
  2114. */
  2115. int
  2116. edit_ext_cmd (WEdit *edit)
  2117. {
  2118. char *exp;
  2119. int e;
  2120. exp =
  2121. input_dialog (_("Paste output of external command"),
  2122. _("Enter shell command(s):"), NULL);
  2123. if (!exp)
  2124. return 1;
  2125. e = system (catstrs (exp, " > ", home_dir, TEMP_FILE, 0));
  2126. g_free (exp);
  2127. if (e) {
  2128. edit_error_dialog (_("External command"),
  2129. get_sys_error (_("Cannot execute command")));
  2130. return -1;
  2131. }
  2132. edit->force |= REDRAW_COMPLETELY;
  2133. edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
  2134. return 0;
  2135. }
  2136. /* if block is 1, a block must be highlighted and the shell command
  2137. processes it. If block is 0 the shell command is a straight system
  2138. command, that just produces some output which is to be inserted */
  2139. void
  2140. edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block)
  2141. {
  2142. long start_mark, end_mark;
  2143. char buf[BUFSIZ];
  2144. FILE *script_home = NULL;
  2145. FILE *script_src = NULL;
  2146. FILE *block_file = NULL;
  2147. char *o = NULL;
  2148. char *h = NULL;
  2149. char *b = NULL;
  2150. char *quoted_name = NULL;
  2151. o = catstrs (mc_home, shell_cmd, 0); /* original source script */
  2152. h = catstrs (home_dir, EDIT_DIR, shell_cmd, 0); /* home script */
  2153. b = catstrs (home_dir, BLOCK_FILE, 0); /* block file */
  2154. if (!(script_home = fopen (h, "r"))) {
  2155. if (!(script_home = fopen (h, "w"))) {
  2156. edit_error_dialog ("", get_sys_error (catstrs
  2157. (_
  2158. ("Error creating script:"),
  2159. h, 0)));
  2160. return;
  2161. }
  2162. if (!(script_src = fopen (o, "r"))) {
  2163. fclose (script_home);
  2164. unlink (h);
  2165. edit_error_dialog ("", get_sys_error (catstrs
  2166. (_("Error reading script:"),
  2167. o, 0)));
  2168. return;
  2169. }
  2170. while (fgets (buf, sizeof (buf), script_src))
  2171. fputs (buf, script_home);
  2172. if (fclose (script_home)) {
  2173. edit_error_dialog ("", get_sys_error (catstrs
  2174. (_
  2175. ("Error closing script:"),
  2176. h, 0)));
  2177. return;
  2178. }
  2179. chmod (h, 0700);
  2180. edit_error_dialog ("", get_sys_error (catstrs
  2181. (_("Script created:"), h, 0)));
  2182. }
  2183. open_error_pipe ();
  2184. if (block) { /* for marked block run indent formatter */
  2185. if (eval_marks (edit, &start_mark, &end_mark)) {
  2186. edit_error_dialog (_("Process block"),
  2187. _
  2188. (" You must first highlight a block of text. "));
  2189. return;
  2190. }
  2191. edit_save_block (edit, b, start_mark, end_mark);
  2192. quoted_name = name_quote (edit->filename, 0);
  2193. /*
  2194. * Run script.
  2195. * Initial space is to avoid polluting bash history.
  2196. * Arguments:
  2197. * $1 - name of the edited file (to check its extension etc).
  2198. * $2 - file containing the current block.
  2199. * $3 - file where error messages should be put
  2200. * (for compatibility with old scripts).
  2201. */
  2202. system (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ", quoted_name,
  2203. " ", home_dir, BLOCK_FILE " /dev/null", NULL));
  2204. } else {
  2205. /*
  2206. * No block selected, just execute the command for the file.
  2207. * Arguments:
  2208. * $1 - name of the edited file.
  2209. */
  2210. system (catstrs (" ", home_dir, EDIT_DIR, shell_cmd, " ",
  2211. quoted_name, NULL));
  2212. }
  2213. g_free (quoted_name);
  2214. close_error_pipe (0, 0);
  2215. edit_refresh_cmd (edit);
  2216. edit->force |= REDRAW_COMPLETELY;
  2217. /* insert result block */
  2218. if (block) {
  2219. if (edit_block_delete_cmd (edit))
  2220. return;
  2221. edit_insert_file (edit, b);
  2222. if ((block_file = fopen (b, "w")))
  2223. fclose (block_file);
  2224. return;
  2225. }
  2226. return;
  2227. }
  2228. /* prints at the cursor */
  2229. /* returns the number of chars printed */
  2230. int edit_print_string (WEdit * e, const char *s)
  2231. {
  2232. int i = 0;
  2233. while (s[i])
  2234. edit_execute_cmd (e, -1, (unsigned char) s[i++]);
  2235. e->force |= REDRAW_COMPLETELY;
  2236. edit_update_screen (e);
  2237. return i;
  2238. }
  2239. int edit_printf (WEdit * e, const char *fmt, ...)
  2240. {
  2241. int i;
  2242. va_list pa;
  2243. char s[1024];
  2244. va_start (pa, fmt);
  2245. g_vsnprintf (s, sizeof (s), fmt, pa);
  2246. i = edit_print_string (e, s);
  2247. va_end (pa);
  2248. return i;
  2249. }
  2250. /* FIXME: does this function break NT_OS2 ? */
  2251. static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
  2252. {
  2253. FILE *p = 0;
  2254. char *s;
  2255. to = name_quote (to, 0);
  2256. subject = name_quote (subject, 0);
  2257. cc = name_quote (cc, 0);
  2258. s = g_strdup_printf ("mail -s %s -c %s %s", subject, cc, to);
  2259. g_free (to);
  2260. g_free (subject);
  2261. g_free (cc);
  2262. if (s) {
  2263. p = popen (s, "w");
  2264. g_free (s);
  2265. }
  2266. if (p) {
  2267. long i;
  2268. for (i = 0; i < edit->last_byte; i++)
  2269. fputc (edit_get_byte (edit, i), p);
  2270. pclose (p);
  2271. }
  2272. }
  2273. #define MAIL_DLG_HEIGHT 12
  2274. void edit_mail_dialog (WEdit * edit)
  2275. {
  2276. char *tmail_to;
  2277. char *tmail_subject;
  2278. char *tmail_cc;
  2279. static char *mail_cc_last = 0;
  2280. static char *mail_subject_last = 0;
  2281. static char *mail_to_last = 0;
  2282. QuickDialog Quick_input =
  2283. {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
  2284. "[Input Line Keys]", 0};
  2285. QuickWidget quick_widgets[] =
  2286. {
  2287. {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, N_("&Cancel"), 0, B_CANCEL, 0,
  2288. 0, NULL},
  2289. {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, N_("&OK"), 0, B_ENTER, 0,
  2290. 0, NULL},
  2291. {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
  2292. 0, "mail-dlg-input"},
  2293. {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, N_(" Copies to"), 0, 0, 0,
  2294. 0, 0},
  2295. {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
  2296. 0, "mail-dlg-input-2"},
  2297. {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, N_(" Subject"), 0, 0, 0,
  2298. 0, 0},
  2299. {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
  2300. 0, "mail-dlg-input-3"},
  2301. {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, N_(" To"), 0, 0, 0,
  2302. 0, 0},
  2303. {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, N_(" mail -s <subject> -c <cc> <to>"), 0, 0, 0,
  2304. 0, 0},
  2305. {0}};
  2306. quick_widgets[2].str_result = &tmail_cc;
  2307. quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
  2308. quick_widgets[4].str_result = &tmail_subject;
  2309. quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
  2310. quick_widgets[6].str_result = &tmail_to;
  2311. quick_widgets[6].text = mail_to_last ? mail_to_last : "";
  2312. Quick_input.widgets = quick_widgets;
  2313. if (quick_dialog (&Quick_input) != B_CANCEL) {
  2314. if (mail_cc_last)
  2315. g_free (mail_cc_last);
  2316. if (mail_subject_last)
  2317. g_free (mail_subject_last);
  2318. if (mail_to_last)
  2319. g_free (mail_to_last);
  2320. mail_cc_last = *(quick_widgets[2].str_result);
  2321. mail_subject_last = *(quick_widgets[4].str_result);
  2322. mail_to_last = *(quick_widgets[6].str_result);
  2323. pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
  2324. }
  2325. }
  2326. /*******************/
  2327. /* Word Completion */
  2328. /*******************/
  2329. /* find first character of current word */
  2330. static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
  2331. {
  2332. int i, c, last;
  2333. /* return if at begin of file */
  2334. if (edit->curs1 <= 0)
  2335. return 0;
  2336. c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
  2337. /* return if not at end or in word */
  2338. if (isspace (c) || !(isalnum (c) || c == '_'))
  2339. return 0;
  2340. /* search start of word to be completed */
  2341. for (i = 2;; i++) {
  2342. /* return if at begin of file */
  2343. if (edit->curs1 - i < 0)
  2344. return 0;
  2345. last = c;
  2346. c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
  2347. if (!(isalnum (c) || c == '_')) {
  2348. /* return if word starts with digit */
  2349. if (isdigit (last))
  2350. return 0;
  2351. *word_start = edit->curs1 - (i - 1); /* start found */
  2352. *word_len = i - 1;
  2353. break;
  2354. }
  2355. }
  2356. /* success */
  2357. return 1;
  2358. }
  2359. /* (re)set search parameters to the given values */
  2360. static void edit_set_search_parameters (int rs, int rb, int rr, int rw, int rc)
  2361. {
  2362. replace_scanf = rs;
  2363. replace_backwards = rb;
  2364. replace_regexp = rr;
  2365. replace_whole = rw;
  2366. replace_case = rc;
  2367. }
  2368. #define MAX_WORD_COMPLETIONS 100 /* in listbox */
  2369. /* collect the possible completions */
  2370. static int
  2371. edit_collect_completions (WEdit *edit, long start, int word_len,
  2372. char *match_expr, struct selection *compl,
  2373. int *num)
  2374. {
  2375. int len, max_len = 0, i, skip;
  2376. char *bufpos;
  2377. /* collect max MAX_WORD_COMPLETIONS completions */
  2378. while (*num < MAX_WORD_COMPLETIONS) {
  2379. /* get next match */
  2380. start =
  2381. edit_find (start - 1, (unsigned char *) match_expr, &len,
  2382. edit->last_byte,
  2383. (int (*)(void *, long)) edit_get_byte,
  2384. (void *) edit, 0);
  2385. /* not matched */
  2386. if (start < 0)
  2387. break;
  2388. /* add matched completion if not yet added */
  2389. bufpos =
  2390. &edit->
  2391. buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE];
  2392. skip = 0;
  2393. for (i = 0; i < *num; i++) {
  2394. if (strncmp
  2395. (&compl[i].text[word_len], &bufpos[word_len],
  2396. max (len, compl[i].len) - word_len) == 0) {
  2397. skip = 1;
  2398. break; /* skip it, already added */
  2399. }
  2400. }
  2401. if (skip)
  2402. continue;
  2403. compl[*num].text = g_malloc (len + 1);
  2404. compl[*num].len = len;
  2405. for (i = 0; i < len; i++)
  2406. compl[*num].text[i] = *(bufpos + i);
  2407. compl[*num].text[i] = '\0';
  2408. (*num)++;
  2409. /* note the maximal length needed for the completion dialog */
  2410. if (len > max_len)
  2411. max_len = len;
  2412. }
  2413. return max_len;
  2414. }
  2415. /* let the user select its preferred completion */
  2416. static void
  2417. edit_completion_dialog (WEdit *edit, int max_len, int word_len,
  2418. struct selection *compl, int num_compl)
  2419. {
  2420. int start_x, start_y, offset, i;
  2421. char *curr = NULL;
  2422. Dlg_head *compl_dlg;
  2423. WListbox *compl_list;
  2424. unsigned int compl_dlg_h; /* completion dialog height */
  2425. unsigned int compl_dlg_w; /* completion dialog width */
  2426. /* calculate the dialog metrics */
  2427. compl_dlg_h = num_compl + 2;
  2428. compl_dlg_w = max_len + 4;
  2429. start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2);
  2430. start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
  2431. if (start_x < 0)
  2432. start_x = 0;
  2433. if (compl_dlg_w > COLS)
  2434. compl_dlg_w = COLS;
  2435. if (compl_dlg_h > LINES - 2)
  2436. compl_dlg_h = LINES - 2;
  2437. offset = start_x + compl_dlg_w - COLS;
  2438. if (offset > 0)
  2439. start_x -= offset;
  2440. offset = start_y + compl_dlg_h - LINES;
  2441. if (offset > 0)
  2442. start_y -= (offset + 1);
  2443. /* create the dialog */
  2444. compl_dlg =
  2445. create_dlg (start_y, start_x, compl_dlg_h, compl_dlg_w,
  2446. dialog_colors, NULL, "[Completion]", NULL,
  2447. DLG_COMPACT);
  2448. /* create the listbox */
  2449. compl_list =
  2450. listbox_new (1, 1, compl_dlg_w - 2, compl_dlg_h - 2, 0, NULL);
  2451. /* add the dialog */
  2452. add_widget (compl_dlg, compl_list);
  2453. /* fill the listbox with the completions */
  2454. for (i = 0; i < num_compl; i++)
  2455. listbox_add_item (compl_list, 0, 0, compl[i].text, NULL);
  2456. /* pop up the dialog */
  2457. run_dlg (compl_dlg);
  2458. /* apply the choosen completion */
  2459. if (compl_dlg->ret_value == B_ENTER) {
  2460. listbox_get_current (compl_list, &curr, NULL);
  2461. if (curr)
  2462. for (curr += word_len; *curr; curr++)
  2463. edit_insert (edit, *curr);
  2464. }
  2465. /* destroy dialog before return */
  2466. destroy_dlg (compl_dlg);
  2467. }
  2468. /*
  2469. * Complete current word using regular expression search
  2470. * backwards beginning at the current cursor position.
  2471. */
  2472. void
  2473. edit_complete_word_cmd (WEdit *edit)
  2474. {
  2475. int word_len = 0, i, num_compl = 0, max_len;
  2476. long word_start = 0;
  2477. char *bufpos;
  2478. char match_expr[MAX_REPL_LEN];
  2479. struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */
  2480. /* don't want to disturb another search */
  2481. int old_rs = replace_scanf;
  2482. int old_rb = replace_backwards;
  2483. int old_rr = replace_regexp;
  2484. int old_rw = replace_whole;
  2485. int old_rc = replace_case;
  2486. /* search start of word to be completed */
  2487. if (!edit_find_word_start (edit, &word_start, &word_len))
  2488. return;
  2489. /* prepare match expression */
  2490. bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
  2491. [word_start & M_EDIT_BUF_SIZE];
  2492. strncpy (match_expr, bufpos, word_len);
  2493. match_expr[word_len] = '\0';
  2494. strcat (match_expr, "[a-zA-Z_0-9]+");
  2495. /* init search: backward, regexp, whole word, case sensitive */
  2496. edit_set_search_parameters (0, 1, 1, 1, 1);
  2497. /* collect the possible completions */
  2498. /* start search from curs1 down to begin of file */
  2499. max_len =
  2500. edit_collect_completions (edit, word_start, word_len, match_expr,
  2501. (struct selection *) &compl, &num_compl);
  2502. if (num_compl > 0) {
  2503. /* insert completed word if there is only one match */
  2504. if (num_compl == 1) {
  2505. for (i = word_len; i < compl[0].len; i++)
  2506. edit_insert (edit, *(compl[0].text + i));
  2507. }
  2508. /* more than one possible completion => ask the user */
  2509. else {
  2510. /* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
  2511. /* !!! pressed again the selection dialog pops up, but that !!! */
  2512. /* !!! seems to require a further internal state !!! */
  2513. /*beep (); */
  2514. /* let the user select the preferred completion */
  2515. edit_completion_dialog (edit, max_len, word_len,
  2516. (struct selection *) &compl,
  2517. num_compl);
  2518. }
  2519. }
  2520. /* release memory before return */
  2521. for (i = 0; i < num_compl; i++)
  2522. g_free (compl[i].text);
  2523. /* restore search parameters */
  2524. edit_set_search_parameters (old_rs, old_rb, old_rr, old_rw, old_rc);
  2525. }