13
13
/* Static variables for this file. */
15
15
/* The valid edbrowse commands. */
16
static const char valid_cmd[] = "aAbBcdefghHijJklmMnpqrstuvwz=^<";
16
static const char valid_cmd[] = "aAbBcdefghHijJklmMnpqrstuvwXz=^<";
17
17
/* Commands that can be done in browse mode. */
18
static const char browse_cmd[] = "AbBdefghHijJklmMnpqsuvwz=^<";
18
static const char browse_cmd[] = "AbBdefghHijJklmMnpqsuvwXz=^<";
19
19
/* Commands for sql mode. */
20
static const char sql_cmd[] = "AadefghHiklmnpqrsvwz=^<";
20
static const char sql_cmd[] = "AadefghHiklmnpqrsvwXz=^<";
21
21
/* Commands for directory mode. */
22
static const char dir_cmd[] = "AdefghHklmnpqsvwz=^<";
22
static const char dir_cmd[] = "AdefghHklmnpqsvwXz=^<";
23
23
/* Commands that work at line number 0, in an empty file. */
24
24
static const char zero_cmd[] = "aAbefhHMqruw=^<";
25
25
/* Commands that expect a space afterward. */
26
26
static const char spaceplus_cmd[] = "befrw";
27
27
/* Commands that should have no text after them. */
28
static const char nofollow_cmd[] = "aAcdhHjlmnptu=";
28
static const char nofollow_cmd[] = "aAcdhHjlmnptuX=";
29
29
/* Commands that can be done after a g// global directive. */
30
static const char global_cmd[] = "dijJlmnpst";
30
static const char global_cmd[] = "dijJlmnpstX";
32
32
static struct ebWindow preWindow, undoWindow;
33
33
static int startRange, endRange; /* as in 57,89p */
139
139
pst p; /* the resulting copy of the string */
142
errorPrint("@invalid session %d in fetchLineContext()", cx);
142
i_printfExit(MSG_InvalidSession, cx);
145
145
if(n <= 0 || n > dol)
146
errorPrint("@invalid line number %d in fetchLineContext()", n);
146
i_printfExit(MSG_InvalidLineNb, n);
148
148
t = map + LNWIDTH * n;
150
150
if(!textLines[idx])
151
errorPrint("@line %d->%d became null", n, idx);
151
i_printfExit(MSG_LineNull, n, idx);
153
153
return textLines[idx];
154
154
p = clonePstring(textLines[idx]);
403
403
debugPrint(6, "freeWindowLines = %d", cnt);
404
404
} /* freeWindowLines */
406
/* quick sort compare */
408
qscmp(const void *s, const void *t)
410
return memcmp(s, t, 6);
406
413
/* Free any lines not used by the snapshot of the current session. */
408
415
freeUndoLines(const char *cmap)
410
417
char *map = undoWindow.map;
420
int diff, ln, cnt = 0;
417
423
debugPrint(6, "freeUndoLines = null");
428
/* This is pretty efficient most of the time,
429
* real inefficient sometimes. */
434
/* sort both arrays, run comm, and find out which lines are not needed any more,
436
* Use quick sort; some files are 100,000 lines long.
437
* I have to copy the second array, so I can sort it.
438
* The first I can sort in place, cause it's going to get thrown away. */
440
cmap2 = cloneString(cmap);
441
qsort(map + LNWIDTH, (strlen(map) / LNWIDTH) - 1, LNWIDTH, qscmp);
442
qsort(cmap2 + LNWIDTH, (strlen(cmap2) / LNWIDTH) - 1, LNWIDTH, qscmp);
430
444
s = map + LNWIDTH;
432
for(; *s && *t; s += LNWIDTH, t += LNWIDTH)
438
if(*s) { /* more to do */
439
s = map + strlen(map);
440
t = cmap + strlen(cmap);
441
s -= LNWIDTH, t -= LNWIDTH;
442
while(s > map && t > cmap) {
445
s -= LNWIDTH, t -= LNWIDTH;
448
/* Ok, who's left? */
449
for(s = map + LNWIDTH; *s; s += LNWIDTH) {
451
continue; /* in use */
452
for(t = cmap + LNWIDTH; *t; t += LNWIDTH)
456
continue; /* in use */
447
diff = memcmp(s, t, 6);
457
/* This line isn't being used any more. */
467
479
undoWindow.map = 0;
468
480
debugPrint(6, "freeUndoLines = %d", cnt);
496
508
cxCompare(int cx)
499
setError("session 0 is invalid");
511
setError(MSG_Session0);
502
514
if(cx >= MAXSESSION) {
503
setError("session %d is out of bounds, limit %d", cx, MAXSESSION - 1);
515
setError(MSG_SessionHigh, cx, MAXSESSION - 1);
506
518
if(cx != context)
507
519
return true; /* ok */
508
setError("you are already in session %d", cx);
520
setError(MSG_SessionCurrent, cx);
516
528
if(cx <= 0 || cx >= MAXSESSION)
517
errorPrint("@session %d out of range in cxActive", cx);
529
i_printfExit(MSG_SessionOutRange, cx);
518
530
if(sessionList[cx].lw)
520
setError("session %d is not active", cx);
532
setError(MSG_SessionInactive, cx);
527
539
struct ebWindow *lw = createWindow();
528
540
if(sessionList[cx].lw)
529
errorPrint("@double init on session %d", cx);
541
i_printfExit(MSG_DoubleInit, cx);
530
542
sessionList[cx].fw = sessionList[cx].lw = lw;
536
548
struct ebWindow *w = sessionList[cx].lw;
538
errorPrint("@quitting a nonactive session %d", cx);
550
i_printfExit(MSG_QuitNoActive, cx);
540
552
/* We might be trashing data, make sure that's ok. */
541
553
if(w->changeMode &&
542
554
!(w->dirMode | w->sqlMode) && lastq != cx && w->fileName &&
543
555
!isURL(w->fileName)) {
545
setError("expecting `w'");
557
setError(MSG_ExpectW);
546
558
if(cx != context)
547
setError("expecting `w' on session %d", cx);
559
setError(MSG_ExpectWX, cx);
839
850
static char path[ABSPATH];
840
851
if(strlen(cw->baseDirName) + strlen(f) > ABSPATH - 2) {
841
setError("absolute path name too long, limit %d chars", ABSPATH);
852
setError(MSG_PathNameLong, ABSPATH);
844
855
sprintf(path, "%s/%s", cw->baseDirName, f);
854
("directories are readonly, type dw to enable directory writes");
864
setError(MSG_DirNoWrite);
857
867
if(dirWrite == 1 && !recycleBin) {
859
("could not create .recycle under your home directory, to hold the deleted files");
868
setError(MSG_NoRecycle);
866
875
file = (char *)fetchLine(ln, 0);
867
876
t = strchr(file, '\n');
869
errorPrint("@no newline on directory entry %s", file);
878
i_printfExit(MSG_NoNlOnDir, file);
871
880
path = makeAbsPath(file);
884
893
char bin[ABSPATH];
885
894
sprintf(bin, "%s/%s", recycleBin, file);
886
895
if(rename(path, bin)) {
888
("Could not move %s to the recycle bin, set dx mode to actually remove the file",
896
setError(MSG_NoMoveToTrash, file);
914
921
int lowcut, highcut, diff, i;
916
923
if(dl > sr && dl < er) {
917
setError("destination lies inside the block to be moved or copied");
924
setError(MSG_DestInBlock);
920
927
if(cmd == 'm' && (dl == er || dl == sr)) {
922
setError("no change");
929
setError(MSG_NoChange);
1049
1056
if(isSQL(filename)) {
1050
1057
const char *t1, *t2;
1051
1058
if(!cw->sqlMode) {
1052
setError("cannot read from the database into another file");
1059
setError(MSG_DBOtherFile);
1055
1062
t1 = strchr(cw->fileName, ']');
1056
1063
t2 = strchr(filename, ']');
1057
1064
if(t1 - cw->fileName != t2 - filename ||
1058
1065
memcmp(cw->fileName, filename, t2 - filename)) {
1059
setError("cannot read different tables into the same session");
1066
setError(MSG_DBOtherTable);
1062
1069
rc = sqlReadRows(filename, &rbuf);
1239
1246
if(memEqualCI(name, "file://", 7))
1242
setError("missing file name");
1249
setError(MSG_MissingFileName);
1245
1252
if(isURL(name)) {
1246
setError("cannot write to a url");
1253
setError(MSG_NoWriteURL);
1249
1256
if(isSQL(name)) {
1250
setError("cannot write to a database table");
1257
setError(MSG_WriteDB);
1254
setError("cannot write an empty file");
1261
setError(MSG_WriteEmpty);
1257
1264
/* mode should be TRUNC or APPEND */
1260
1267
mode |= O_BINARY;
1261
1268
fh = open(name, mode, 0666);
1263
setError("cannot create %s", name);
1270
setError(MSG_NoCreate2, name);
1274
1281
if(write(fh, p, len) < len) {
1276
setError("cannot write to %s", name);
1283
setError(MSG_NoWrite2, name);
1789
1796
} else if(first == '\'' && islowerByte(line[1])) {
1790
1797
ln = cw->labels[line[1] - 'a'];
1792
setError("label %c not set", line[1]);
1799
setError(MSG_NoLabel, line[1]);
1800
1807
char incr; /* forward or back */
1801
1808
/* Don't look through an empty buffer. */
1802
1809
if(cw->dol == 0) {
1803
setError("empty buffer");
1810
setError(MSG_EmptyBuffer);
1806
1813
if(!regexpCheck(line, true, true, &re, &line))
1819
1826
re_opt |= PCRE_CASELESS;
1820
1827
re_cc = pcre_compile(re, re_opt, &re_error, &re_offset, 0);
1822
setError("error in regular expression, %s", re_error);
1829
setError(MSG_RexpError, re_error);
1825
1832
/* We should probably study the pattern, if the file is large.
1841
1848
if(re_count < -1) {
1842
1849
pcre_free(re_cc);
1844
("unexpected error while evaluating the regular expression at line %d",
1850
setError(MSG_RexpError2, ln);
1846
1851
return (globSub = false);
1848
1853
if(re_count >= 0)
1850
1855
if(ln == cw->dot) {
1851
1856
pcre_free(re_cc);
1852
setError("search string not found");
1857
setError(MSG_NotFound);
1855
1860
} /* loop over lines */
1896
1901
int i, origdot, yesdot, nodot;
1899
setError("no regular expression after %c", icmd);
1904
setError(MSG_RexpMissing, icmd);
1903
1908
if(!regexpCheck(line, true, true, &re, &line))
1905
1910
if(*line != delim) {
1906
setError("missing delimiter");
1911
setError(MSG_NoDelimit);
1921
1926
re_opt |= PCRE_CASELESS;
1922
1927
re_cc = pcre_compile(re, re_opt, &re_error, &re_offset, 0);
1924
setError("error in regular expression, %s", re_error);
1929
setError(MSG_RexpError, re_error);
1927
1932
for(i = startRange; i <= endRange; ++i) {
1998
1999
cw->dot = origdot;
1999
2000
if(!errorMsg[0])
2000
setError("none of the marked lines were successfully modified");
2001
setError(MSG_NotModifiedG);
2002
2003
if(!errorMsg[0] && intFlag)
2004
setError(MSG_Interrupted);
2004
2005
return (errorMsg[0] == 0);
2005
2006
} /* doGlobal */
2008
fieldNumProblem(const char *desc, char c, int n, int nt, int nrt)
2009
fieldNumProblem(int desc, char c, int n, int nt, int nrt)
2011
setError("no %s present", desc);
2012
setError(MSG_NoInputFields + desc);
2015
setError("multiple %s present, please use %c1 through %c%d", desc, c, c,
2016
setError(MSG_ManyInputFields + desc, c, c, nt);
2020
setError("%d is out of range, please use %c1 through %c%d", n, c, c,
2020
setError(MSG_InputRange, n, c, c, nt);
2023
setError("%d is out of range, please use %c1, or simply %c", n, c, c);
2022
setError(MSG_InputRange2, n, c, c);
2024
2023
} /* fieldNumProblem */
2026
2025
/* Perform a substitution on a given line.
2047
2046
/* find the next match */
2048
2047
re_count = pcre_exec(re_cc, 0, line, len, offset, 0, re_vector, 33);
2049
2048
if(re_count < -1) {
2051
("unexpected error while evaluating the regular expression at line %d",
2049
setError(MSG_RexpError2, ln);
2055
2052
if(re_count < 0)
2058
2055
lastoffset = offset;
2059
2056
offset = re_vector[1]; /* ready for next iteration */
2060
2057
if(offset == lastoffset && (nth > 1 || global)) {
2061
setError("cannot replace multiple instances of the empty string");
2058
setError(MSG_ManyEmptyStrings);
2064
2061
if(!global &&instance != nth)
2228
2225
if(isdigitByte(*line))
2229
2226
whichField = strtol(line, (char **)&line, 10);
2231
setError("no regular expression after %c", icmd);
2228
setError(MSG_RexpMissing2, icmd);
2235
2232
if(cw->dirMode && !dirWrite) {
2237
("directories are readonly, type dw to enable directory writes");
2233
setError(MSG_DirNoWrite);
2271
2267
if(isdigitByte(c)) {
2273
setError("multiple numbers after the third delimiter");
2269
setError(MSG_SubNumbersMany);
2276
2272
nth = strtol(line, (char **)&line, 10);
2280
("unexpected substitution suffix after the third delimiter");
2275
setError(MSG_SubSuffixBad);
2282
2277
} /* loop gathering suffix flags */
2283
2278
if(g_mode && nth) {
2285
("cannot use both a numeric suffix and the `g' suffix simultaneously");
2279
setError(MSG_SubNumberG);
2288
2282
} /* closing delimiter */
2294
2288
re_opt |= PCRE_CASELESS;
2295
2289
re_cc = pcre_compile(lhs, re_opt, &re_error, &re_offset, 0);
2297
setError("error in regular expression, %s", re_error);
2291
setError(MSG_RexpError, re_error);
2314
2308
if(!breakLine(p, len, &newlen)) {
2316
("sorry, cannot apply the bl command to lines longer than %d bytes",
2309
setError(MSG_BreakLong, REPLACELINELEN);
2320
2312
/* empty line is not allowed */
2334
2326
char search[20];
2335
2327
findInputField(p, 1, whichField, &total, &realtotal, &tagno);
2337
fieldNumProblem("input fields", 'i', whichField, total,
2329
fieldNumProblem(0, 'i', whichField, total, realtotal);
2341
2332
sprintf(search, "%c%d<", InternalCodeChar, tagno);
2390
2381
/* move the file, then update the text */
2391
2382
char src[ABSPATH], *dest;
2392
2383
if(slashcount + nullcount + linecount) {
2394
("cannot embed slash, newline, or null in a directory name");
2384
setError(MSG_DirNameBad);
2397
2387
p[len - 1] = 0; /* temporary */
2407
2397
if(!stringEqual(src, dest)) {
2408
2398
if(fileTypeByName(dest, true)) {
2409
setError("destination file already exists");
2399
setError(MSG_DestFileExists);
2412
2402
if(rename(src, dest)) {
2413
setError("cannot rename file to %s", dest);
2403
setError(MSG_NoRename, dest);
2416
2406
} /* source and dest are different */
2419
2409
if(cw->browseMode) {
2420
2410
if(nullcount) {
2421
setError("cannot embed nulls in an input field");
2411
setError(MSG_InputNull2);
2424
2414
if(linecount) {
2425
setError("cannot embed newlines in an input field");
2415
setError(MSG_InputNewline2);
2428
2418
replaceLine[replaceLineLen] = 0;
2563
2553
char cwdbuf[ABSPATH];
2565
2555
if(!getcwd(cwdbuf, sizeof (cwdbuf))) {
2566
setError("could not %s directory",
2567
(c ? "print new" : "establish current"));
2556
setError(c ? MSG_CDGetError : MSG_CDSetError);
2587
2576
const char *suffix = 0;
2588
2577
bool trailPercent = false;
2590
setError("cannot play an empty buffer");
2579
setError(MSG_AudioEmpty);
2593
2582
if(cw->browseMode) {
2594
setError("cannot play in browse mode");
2583
setError(MSG_AudioBrowse);
2597
2586
if(cw->dirMode) {
2598
setError("cannot play in directory mode");
2587
setError(MSG_AudioDir);
2601
2590
if(cw->sqlMode) {
2602
setError("cannot play in database mode");
2591
setError(MSG_AudioDB);
2608
2597
if(cw->fileName)
2609
2598
suffix = strrchr(cw->fileName, '.');
2612
("file has no suffix, use mt.xxx to specify your own suffix");
2600
setError(MSG_NoSuffix);
2617
2605
if(strlen(suffix) > 5) {
2618
setError("suffix is limited to 5 characters");
2606
setError(MSG_SuffixLong);
2621
2609
mt = findMimeBySuffix(suffix);
2624
("suffix .%s is not a recognized mime type, please check your config file.",
2611
setError(MSG_SuffixBad, suffix);
2628
2614
if(mt->program[strlen(mt->program) - 1] == '%')
2725
2711
if(!cw->fileName) {
2726
setError("no file name or url to refresh");
2712
setError(MSG_NoRefresh);
2729
2715
t = strrchr(cw->fileName, '/');
2731
setError("file name does not contain /");
2717
setError(MSG_NoSlash);
2736
setError("file name ends in /");
2722
setError(MSG_YesSlash);
2739
2725
sprintf(newline, "%c `%s", cmd, t);
2743
2729
if(line[0] == 'f' && line[2] == 0 &&
2744
2730
(line[1] == 'd' || line[1] == 'k' || line[1] == 't')) {
2747
2734
if(!cw->browseMode) {
2748
setError("not in browse mode");
2735
setError(MSG_NoBrowse);
2751
2738
if(line[1] == 't')
2752
s = cw->ft, t = "title";
2739
s = cw->ft, t = MSG_NoTitle;
2753
2740
if(line[1] == 'd')
2754
s = cw->fd, t = "description";
2741
s = cw->fd, t = MSG_NoDesc;
2755
2742
if(line[1] == 'k')
2756
s = cw->fk, t = "keywords";
2743
s = cw->fk, t = MSG_NoKeywords;
2760
printf("no %s\n", t);
2784
2771
if(stringEqual(line, "sg")) {
2785
2772
searchStringsAll = true;
2786
2773
if(helpMessagesOn)
2787
puts("substitutions global");
2774
i_puts(MSG_SubGlobal);
2791
2778
if(stringEqual(line, "sl")) {
2792
2779
searchStringsAll = false;
2793
2780
if(helpMessagesOn)
2794
puts("substitutions local");
2781
i_puts(MSG_SubLocal);
2798
2785
if(stringEqual(line, "ci")) {
2799
2786
caseInsensitive = true;
2800
2787
if(helpMessagesOn)
2801
puts("case insensitive");
2788
i_puts(MSG_CaseIns);
2805
2792
if(stringEqual(line, "cs")) {
2806
2793
caseInsensitive = false;
2807
2794
if(helpMessagesOn)
2808
puts("case sensitive");
2795
i_puts(MSG_CaseSen);
2812
2799
if(stringEqual(line, "dr")) {
2814
2801
if(helpMessagesOn)
2815
puts("directories readonly");
2802
i_puts(MSG_DirReadonly);
2819
2806
if(stringEqual(line, "dw")) {
2821
2808
if(helpMessagesOn)
2822
puts("directories writable");
2809
i_puts(MSG_DirWritable);
2826
2813
if(stringEqual(line, "dx")) {
2828
2815
if(helpMessagesOn)
2829
puts("directories writable with delete");
2833
2820
if(stringEqual(line, "hr")) {
2834
2821
allowRedirection ^= 1;
2835
2822
if(helpMessagesOn || debugLevel >= 1)
2836
puts(allowRedirection ? "http redirection" : "no http redirection");
2823
i_puts(allowRedirection + MSG_RedirectionOff);
2840
2827
if(stringEqual(line, "sr")) {
2841
2828
sendReferrer ^= 1;
2842
2829
if(helpMessagesOn || debugLevel >= 1)
2843
puts(sendReferrer ? "send referrer" : "do not send referrer");
2830
i_puts(sendReferrer + MSG_RefererOff);
2847
2834
if(stringEqual(line, "js")) {
2849
2836
if(helpMessagesOn || debugLevel >= 1)
2850
puts(allowJS ? "javascript enabled" : "javascript disabled");
2837
i_puts(allowJS + MSG_JavaOff);
2854
2841
if(stringEqual(line, "bd")) {
2855
2842
binaryDetect ^= 1;
2856
2843
if(helpMessagesOn || debugLevel >= 1)
2857
puts(binaryDetect ? "watching for binary files" :
2858
"treating binary like text");
2844
i_puts(binaryDetect + MSG_BinaryIgnore);
2869
2855
if(helpMessagesOn || debugLevel >= 1) {
2870
2856
if(ftpMode == 'F')
2871
puts("passive mode");
2857
i_puts(MSG_PassiveMode);
2872
2858
if(ftpMode == 'E')
2873
puts("active mode");
2859
i_puts(MSG_ActiveMode);
2874
2860
if(ftpMode == 0)
2875
puts("passive/active mode");
2861
i_puts(MSG_PassActMode);
2880
2866
if(stringEqual(line, "vs")) {
2881
2867
verifyCertificates ^= 1;
2882
2868
if(helpMessagesOn || debugLevel >= 1)
2883
puts(verifyCertificates ? "verify ssl connections" :
2884
"don't verify ssl connections (less secure)");
2869
i_puts(verifyCertificates + MSG_CertifyOff);
2885
2870
ssl_must_verify(verifyCertificates);
2889
2874
if(stringEqual(line, "hf")) {
2890
2875
showHiddenFiles ^= 1;
2891
2876
if(helpMessagesOn || debugLevel >= 1)
2892
puts(showHiddenFiles ? "show hidden files in directory mode" :
2893
"don't show hidden files in directory mode");
2877
i_puts(showHiddenFiles + MSG_HiddenOff);
2897
2881
if(stringEqual(line, "tn")) {
2898
2882
textAreaDosNewlines ^= 1;
2899
2883
if(helpMessagesOn || debugLevel >= 1)
2900
puts(textAreaDosNewlines ? "text areas use dos newlines" :
2901
"text areas use unix newlines");
2884
i_puts(textAreaDosNewlines + MSG_AreaUnix);
2905
2888
if(stringEqual(line, "eo")) {
2907
2890
if(helpMessagesOn)
2908
puts("end markers off");
2891
i_puts(MSG_MarkOff);
2912
2895
if(stringEqual(line, "el")) {
2914
2897
if(helpMessagesOn)
2915
puts("end markers on listed lines");
2898
i_puts(MSG_MarkList);
2919
2902
if(stringEqual(line, "ep")) {
2921
2904
if(helpMessagesOn)
2922
puts("end markers on");
2975
2958
static char openlist[] = "{([<`";
2976
2959
static char closelist[] = "})]>'";
2977
static char alllist[] = "{}()[]<>`'";
2960
static const char alllist[] = "{}()[]<>`'";
2980
2963
int i, direction, forward, backward;
2982
2965
if(c = *line) {
2983
2966
if(!strchr(alllist, c) || line[1]) {
2984
setError("you must specify exactly one of %s after the B command",
2967
setError(MSG_BalanceChar, alllist);
2988
2970
if(t = strchr(openlist, c)) {
2997
2979
unbalanced(c, d, endRange, &backward, &forward);
2998
2980
if(direction > 0) {
2999
2981
if((level = forward) == 0) {
3000
setError("line does not contain an open %c", c);
2982
setError(MSG_BalanceNoOpen, c);
3004
2986
if((level = backward) == 0) {
3005
setError("line does not contain an open %c", d);
2987
setError(MSG_BalanceNoOpen, d);
3014
2996
d = closelist[i];
3015
2997
unbalanced(c, d, endRange, &backward, &forward);
3016
2998
if(backward && forward) {
3018
("both %c and %c are unbalanced on this line, try B%c or B%c",
2999
setError(MSG_BalanceAmbig, c, d, c, d);
3022
3002
level = backward + forward;
3032
("line does not contain an unbalanced brace, parenthesis, or bracket");
3011
setError(MSG_BalanceNothing);
3035
3014
} /* explicit character passed in, or look for one */
3066
3045
w = sessionList[cx].lw;
3067
3046
if(w->browseMode) {
3068
setError("session %d is currently in browse mode", cx);
3047
setError(MSG_SessionBrowse, cx);
3071
3050
if(w->dirMode) {
3072
setError("session %d is currently in directory mode", cx);
3051
setError(MSG_SessionDir, cx);
3330
3309
/* Breakline is actually a substitution of lines. */
3331
3310
if(stringEqual(line, "bl")) {
3332
3311
if(cw->dirMode) {
3333
setError("cannot break lines in directory mode");
3312
setError(MSG_BreakDir);
3336
3315
if(cw->sqlMode) {
3337
setError("cannot break lines in database mode");
3316
setError(MSG_BreakDB);
3340
3319
if(cw->browseMode) {
3341
setError("cannot break lines in browse mode");
3320
setError(MSG_BreakBrowse);
3355
3334
if(!strchr(valid_cmd, cmd)) {
3356
setError("unknown command %c", cmd);
3335
setError(MSG_UnknownCommand, cmd);
3357
3336
return (globSub = false);
3363
3342
writeMode = O_APPEND, first = *++line;
3365
3344
if(cw->dirMode && !strchr(dir_cmd, cmd)) {
3366
setError("%c not available in directory mode", icmd);
3345
setError(MSG_DirCommand, icmd);
3367
3346
return (globSub = false);
3369
3348
if(cw->sqlMode && !strchr(sql_cmd, cmd)) {
3370
setError("%c not available in database mode", icmd);
3349
setError(MSG_BadRange, icmd);
3371
3350
return (globSub = false);
3373
3352
if(cw->browseMode && !strchr(browse_cmd, cmd)) {
3374
setError("%c not available in browse mode", icmd);
3353
setError(MSG_BrowseCommand, icmd);
3375
3354
return (globSub = false);
3377
3356
if(startRange == 0 && !strchr(zero_cmd, cmd)) {
3378
setError("zero line number");
3357
setError(MSG_AtLine0);
3379
3358
return (globSub = false);
3381
3360
while(isspaceByte(first))
3385
3364
while(isdigitByte(*s))
3388
setError("no space after command");
3367
setError(MSG_NoSpaceAfter);
3389
3368
return (globSub = false);
3392
3371
if(globSub && !strchr(global_cmd, cmd)) {
3393
setError("the %c command cannot be applied globally", icmd);
3372
setError(MSG_GlobalCommand, icmd);
3394
3373
return (globSub = false);
3400
3379
destLine = cw->dot;
3402
3381
if(!strchr(valid_laddr, first)) {
3403
setError("invalid move/copy destination");
3382
setError(MSG_BadDest);
3404
3383
return (globSub = false);
3406
3385
if(!getRangePart(line, &destLine, &line))
3453
3432
linePending[0] = 0;
3455
3434
if(first && strchr(nofollow_cmd, cmd)) {
3456
setError("unexpected text after the %c command", icmd);
3435
setError(MSG_TextAfter, icmd);
3457
3436
return (globSub = false);
3507
3492
if(cmd == 'k') {
3508
3493
if(!islowerByte(first) || line[1]) {
3509
setError("please enter k[a-z]");
3494
setError(MSG_EnterKAZ);
3512
3497
if(startRange < endRange) {
3513
setError("cannot label an entire range");
3498
setError(MSG_RangeLabel);
3516
3501
cw->labels[first - 'a'] = endRange;
3567
3552
if(!cxActive(cx))
3569
3554
s = sessionList[cx].lw->fileName;
3570
printf("%s", s ? s : "no file");
3558
i_printf(MSG_NoFile);
3571
3559
if(sessionList[cx].lw->binMode)
3572
printf(" [binary]");
3560
i_printf(MSG_BinaryBrackets);
3575
3563
} /* another session */
3577
3565
if(cw->dirMode) {
3578
setError("cannot change the name of a directory");
3566
setError(MSG_DirRename);
3581
3569
if(cw->sqlMode) {
3582
setError("cannot change the name of a table");
3570
setError(MSG_TableRename);
3585
3573
nzFree(cw->fileName);
3586
3574
cw->fileName = cloneString(line);
3588
3576
s = cw->fileName;
3589
printf("%s", s ? s : "no file");
3580
i_printf(MSG_NoFile);
3590
3581
if(cw->binMode)
3591
printf(" [binary]");
3582
i_printf(MSG_BinaryBrackets);
3596
3587
if(cmd == 'w') {
3597
3588
if(cx) { /* write to another buffer */
3598
3589
if(writeMode == O_APPEND) {
3599
setError("cannot append to another buffer");
3590
setError(MSG_BufferAppend);
3602
3593
return writeContext(cx);
3605
3596
line = cw->fileName;
3607
setError("no file specified");
3598
setError(MSG_NoFileSpecified);
3610
3601
if(cw->dirMode && stringEqual(line, cw->fileName)) {
3612
("cannot write to the directory; files are modified as you go");
3602
setError(MSG_NoDirWrite);
3615
3605
if(cw->sqlMode && stringEqual(line, cw->fileName)) {
3617
("cannot write to the database; rows are modified as you go");
3606
setError(MSG_NoDBWrite);
3620
3609
return writeFile(line, writeMode);
3647
3636
if(cmd == 'M') { /* move this to another session */
3648
3637
if(first && !cx) {
3649
setError("unexpected text after the M command");
3638
setError(MSG_MAfter);
3653
setError("destination session not specified");
3642
setError(MSG_NoDestSession);
3656
3645
if(!cw->prev) {
3657
setError("no previous text, cannot back up");
3646
setError(MSG_NoBackup);
3660
3649
if(!cxCompare(cx))
3701
3690
if(cmd == 'g' && cw->dirMode && !first) {
3702
3691
char *p, *dirline, *endline;
3703
3692
if(endRange > startRange) {
3704
setError("cannot apply the g command to a range");
3693
setError(MSG_RangeG);
3707
3696
p = (char *)fetchLine(endRange, -1);
3743
3732
j = strtol(line, (char **)&s, 10);
3744
3733
if(j >= 0 && !*s) {
3745
3734
if(cw->sqlMode) {
3746
setError("g not available in database mode");
3749
3738
jsh = jsgo = nogo = false;
3750
3739
jsdead = cw->jsdead;
3742
click = dclick = over = false;
3754
3744
if(endRange > startRange) {
3755
setError("cannot apply the g command to a range");
3745
setError(MSG_RangeG);
3758
3748
p = (char *)fetchLine(endRange, -1);
3760
3750
findField(p, 0, j, &n, 0, &tagno, &h, &ev);
3761
3751
debugPrint(5, "findField returns %d, %s", tagno, h);
3763
fieldNumProblem("links", 'g', j, n, n);
3753
fieldNumProblem(1, 'g', j, n, n);
3766
3756
jsh = memEqualCI(h, "javascript:", 11);
3778
3768
debugPrint(5, "click %d dclick %d over %d", click, dclick, over);
3779
3769
if(jsgo & jsdead) {
3781
puts("javascript is disabled, no action taken");
3771
i_puts(MSG_NJNoAction);
3783
puts("javascript is disabled, going straight to the url");
3773
i_puts(MSG_NJGoing);
3784
3774
jsgo = jsh = false;
3786
3776
line = allocatedLine = h;
3849
3839
if(c && (strchr(valid_delim, c) || cmd == 'i' && strchr("*<?=", c))) {
3850
3840
if(!cw->browseMode && (cmd == 'i' || cx)) {
3851
setError("not in browse mode");
3841
setError(MSG_NoBrowse);
3854
3844
if(endRange > startRange && cmd == 'i') {
3855
setError("cannot apply the i%c command to a range", c);
3845
setError(MSG_RangeI, c);
3858
3848
if(cmd == 'i' && strchr("?=<*", c)) {
3872
3862
findInputField(p, j, cx, &n, &realtotal, &tagno);
3873
3863
debugPrint(5, "findField returns %d.%d", n, tagno);
3875
fieldNumProblem((c == '*' ? "buttons" : "input fields"),
3876
'i', cx, n, realtotal);
3865
fieldNumProblem((c == '*' ? 2 : 0), 'i', cx, n, realtotal);
3879
3868
if(scmd == '?') {
3900
3889
dol = sessionList[n].lw->dol;
3902
setError("buffer %d is empty", n);
3891
setError(MSG_BufferXEmpty, n);
3906
setError("buffer %d contains more than one line",
3895
setError(MSG_BufferXLines, n);
3910
3898
p = (char *)fetchLineContext(1, 1, n);
3922
3910
fd = open(line, O_RDONLY | O_TEXT);
3924
setError("cannot open %s", line);
3912
setError(MSG_NoOpen, line);
3927
3915
n = read(fd, newline, sizeof (newline));
3930
setError("cannot read from %s", line);
3918
setError(MSG_NoRead, line);
3934
3922
for(j = 0; j < n; ++j) {
3935
3923
if(newline[j] == 0) {
3936
setError("input text contains nulls", line);
3924
setError(MSG_InputNull, line);
3939
3927
if(newline[j] == '\r' && !fromfile &&
3940
3928
j < n - 1 && newline[j + 1] != '\n') {
3942
("line contains an embeded carriage return");
3929
setError(MSG_InputCR);
3945
3932
if(newline[j] == '\r' || newline[j] == '\n')
3948
3935
if(j == sizeof (newline)) {
3949
setError("first line of %s is too long", line);
3936
setError(MSG_FirstLineLong, line);
3952
3939
newline[j] = 0;
3978
3965
if(cmd == 'e' || cmd == 'b' && first && first != '#') {
3979
3966
if(cw->fileName && !noStack && sameURL(line, cw->fileName)) {
3980
3967
if(stringEqual(line, cw->fileName)) {
3982
("file is currently in buffer - please use the rf command to refresh");
3968
setError(MSG_AlreadyInBuffer);
3985
3971
/* Same url, but a different #section */
4098
4083
if(!browseCurrentBuffer()) {
4099
4084
if(icmd == 'b') {
4100
setError("this doesn't look like browsable text");
4085
setError(MSG_Unbrowsable);
4105
4090
} else if(!first) {
4106
setError("already browsing");
4091
setError(MSG_BrowseAlready);
4385
4369
rc = addTextToBuffer((pst) text, textlen, 0);
4388
"warning: could not preload <buffer %d> with its initial text",
4371
i_printf(MSG_BufferPreload, cx);
4390
4372
if(autobrowse) {
4391
4373
/* This is html; we need to render it.
4392
4374
* I'm disabling javascript in this window.
4475
if(memEqualCI(newbuf, "<html>\n", 7)) {
4457
if(memEqualCI(newbuf, "<html>\n", 7) && allowRedirection) {
4476
4458
/* double browse, mail then html */
4478
4460
rawbuf = newbuf;
4605
4587
if(notify == 1)
4606
4588
displayLine(ln);
4607
4589
if(notify == 2)
4608
printf("line %d has been updated\n", ln);
4590
i_printf(MSG_LineUpdated, ln);
4609
4591
cw->firstOpMode = undoable = true;
4614
errorPrint("fieldInBuffer could not find tag %d newtext %s", tagno,
4596
i_printfExit(MSG_NoTagFound, tagno, newtext);
4616
4597
} /* updateFieldInBuffer */
4618
4599
/* This is the inverse of the above function, fetch instead of update. */