1 /*
2 * NAME: valid()
3 * DESCRIPTION: check if a path is valid
4 */
valid(string file,int type)5 private string valid(string file, int type)
6 {
7 object player;
8
9 if (object_name(this_object()) == MASTER) {
10 return file;
11 }
12
13 player = this_player();
14 if (player == 0 || interactive(player) == 0) {
15 return 0;
16 }
17 file = (type == 0) ? player->valid_read(file) : player->valid_write(file);
18 if (player == 0) {
19 return 0;
20 }
21 if (!stringp(file)) {
22 write("Bad file name.\n");
23 return 0;
24 } else if (file != "" &&
25 (file[0] == '/' || sscanf(file, "%*s ") != 0 ||
26 sscanf(file, "%*s..") != 0)) {
27 error("Illegal path: " + file);
28 }
29 return file;
30 }
31
32 /*
33 * NAME: file_size()
34 * DESCRIPTION: get the size of a file
35 */
file_size(string file)36 static int file_size(string file)
37 {
38 int *sizes;
39
40 ARGCHECK(file, file_size, 1);
41 file = valid(file, 0);
42 if (file == 0) {
43 return -1;
44 }
45
46 sizes = ::get_dir(file)[1];
47 if (sizeof(sizes) != 1) {
48 return -1;
49 }
50
51 return sizes[0];
52 }
53
54 /*
55 * NAME: log_file()
56 * DESCRIPTION: log something
57 */
log_file(string file,string str)58 static void log_file(string file, string str)
59 {
60 int *sizes;
61
62 ARGCHECK(file, log_file, 1);
63 ARGCHECK(str, log_file, 2);
64
65 if (sscanf(file, "%*s/") != 0 || strlen(file) > 30) {
66 error("Illegal file name to log_file(" + file + ")");
67 }
68 file = "/log/" + file;
69 sizes = ::get_dir(file)[1];
70 if (sizeof(sizes) == 1 && sizes[0] >= LOG_FILE_SIZE) {
71 ::remove_file(file + ".old");
72 ::rename_file(file, file + ".old");
73 }
74 ::write_file(file, str);
75 }
76
77 /*
78 * NAME: get_dir()
79 * DESCRIPTION: get directory info
80 */
get_dir(string file)81 static string *get_dir(string file)
82 {
83 int len;
84
85 ARGCHECK(file, get_dir, 1);
86 file = valid(file, 0);
87 if (file == 0) {
88 return ({ });
89 }
90
91 len = strlen(file);
92 if (file == "" || file[len - 1] == '/') {
93 file += "*";
94 } else if (len > 1 && file[len - 2 ..] == "/.") {
95 file[len - 1] = '*';
96 }
97 return ::get_dir(file)[0];
98 }
99
100 /*
101 * NAME: mkdir()
102 * DESCRIPTION: make a directory
103 */
mkdir(string file)104 static int mkdir(string file)
105 {
106 ARGCHECK(file, mkdir, 1);
107 file = valid(file, 0);
108 return (file != 0 && ::make_dir(file) != 0);
109 }
110
111 /*
112 * NAME: make_dir()
113 * DESCRIPTION: make a directory
114 */
make_dir(string file)115 static int make_dir(string file)
116 {
117 return mkdir(file);
118 }
119
120 /*
121 * NAME: read_bytes()
122 * DESCRIPTION: read bytes from a file
123 */
read_bytes(string file,int start,int size)124 static varargs string read_bytes(string file, int start, int size)
125 {
126 ARGCHECK(file, read_bytes, 1);
127 file = valid(file, 0);
128 if (file == 0) {
129 return 0;
130 }
131
132 return ::read_file(file, start, size);
133 }
134
135 /*
136 * NAME: read_lines()
137 * DESCRIPTION: return a line range of a file
138 */
read_lines(string file,int first,int num)139 private string *read_lines(string file, int first, int num)
140 {
141 int line, offset, size, *saved;
142 string str, *lines;
143
144 if (first < 0 || num < 0) {
145 return 0;
146 }
147
148 if (first == 0) {
149 first = 1;
150 }
151 line = 1;
152 if (this_user()) {
153 saved = this_user()->query_file_offset(file);
154 if (saved != 0) {
155 line = saved[0];
156 if (line > 2 * first) {
157 line = 1;
158 } else {
159 offset = saved[1];
160 }
161 }
162 }
163
164 for (;;) {
165 if (line <= first) {
166 str = ::read_file(file, offset, FILE_CHUNK);
167 if (str == 0) {
168 return 0;
169 }
170 lines = explode("\n" + str + "\n", "\n");
171 size = sizeof(lines) - 1;
172 if (line == first) {
173 if (num == 0 || size < num) {
174 if (strlen(str) < FILE_CHUNK) {
175 return lines;
176 }
177 error("Line range too large");
178 }
179 }
180 if (size == 0) {
181 if (strlen(str) < FILE_CHUNK) {
182 return 0;
183 }
184 error("Line too long");
185 }
186 } else {
187 offset -= FILE_CHUNK;
188 if (offset < 0) {
189 offset = 0;
190 }
191 str = ::read_file(file, offset, FILE_CHUNK);
192 if (str == 0) {
193 return 0;
194 }
195 lines = explode("\n" + str + "\n", "\n");
196 size = sizeof(lines) - 1;
197 if (offset == 0) {
198 line = 1;
199 } else {
200 if (size == 0) {
201 error("Line too long");
202 } else {
203 --size;
204 line -= size;
205 if (line <= 0) {
206 /* ??? */
207 line = 1;
208 offset = 0;
209 continue;
210 }
211 offset += strlen(lines[0]) + 1;
212 lines = lines[1 ..];
213 }
214 }
215 }
216
217 if (line <= first && line + size > first) {
218 if (num != 0 && line + size >= first + num) {
219 first -= line;
220 if (this_user() != 0) {
221 line += first + num;
222 offset += strlen(implode(lines[0 .. first + num - 1],
223 "\n")) + 1;
224 this_user()->set_file_offset(file, line, offset);
225 }
226 return lines[first .. first + num - 1] + ({ "" });
227 }
228 size = first - line;
229 }
230 if (line < first) {
231 line += size;
232 offset += strlen(implode(lines[0 .. size - 1], "\n")) + 1;
233 }
234 }
235 }
236
237 /*
238 * NAME: read_file()
239 * DESCRIPTION: read a file
240 */
read_file(string file,int first,int num)241 static varargs string read_file(string file, int first, int num)
242 {
243 string *lines;
244
245 ARGCHECK(file, read_file, 1);
246 file = valid(file, 0);
247 if (file == 0) {
248 return 0;
249 }
250
251 if (first == 0 && num == 0) {
252 return ::read_file(file);
253 }
254
255 lines = read_lines(file, first, num);
256 if (lines == 0) {
257 return 0;
258 }
259 return implode(lines, "\n");
260 }
261
262 /*
263 * NAME: rm()
264 * DESCRIPTION: remove a file
265 */
rm(string file)266 static int rm(string file)
267 {
268 ARGCHECK(file, rm, 1);
269 file = valid(file, 1);
270 return (file != 0 && ::remove_file(file));
271 }
272
273 /*
274 * NAME: remove_file()
275 * DESCRIPTION: remove a file
276 */
remove_file(string file)277 static int remove_file(string file)
278 {
279 return rm(file);
280 }
281
282 /*
283 * NAME: rmdir()
284 * DESCRIPTION: remove a directory
285 */
rmdir(string file)286 static int rmdir(string file)
287 {
288 ARGCHECK(file, rmdir, 1);
289 file = valid(file, 1);
290 return (file != 0 && ::remove_dir(file));
291 }
292
293 /*
294 * NAME: remove_dir()
295 * DESCRIPTION: remove a directory
296 */
remove_dir(string file)297 static int remove_dir(string file)
298 {
299 return rmdir(file);
300 }
301
302 /*
303 * NAME: rename()
304 * DESCRIPTION: rename a file
305 */
rename(string from,string to)306 static int rename(string from, string to)
307 {
308 ARGCHECK(from, rename, 1);
309 ARGCHECK(to, rename, 2);
310
311 from = valid(from, 1);
312 if (from == 0) {
313 return 0;
314 }
315 to = valid(to, 1);
316 if (to == 0) {
317 return 0;
318 }
319 return ::rename_file(from, to);
320 }
321
322 /*
323 * NAME: rename_file()
324 * DESCRIPTION: rename a file
325 */
rename_file(string from,string to)326 static int rename_file(string from, string to)
327 {
328 return rename(from, to);
329 }
330
331 /*
332 * NAME: restore_object()
333 * DESCRIPTION: restore an object
334 */
restore_object(string file)335 static int restore_object(string file)
336 {
337 string str, *path;
338
339 ARGCHECK(file, restore_object, 1);
340
341 if (this_object() == 0) {
342 return 0;
343 }
344 if (sscanf(file, "%*s/../") != 0) {
345 error("Illegal restore file name " + file);
346 }
347 path = explode(object_name(this_object()), "/");
348 switch (path[0]) {
349 case "players":
350 if (sscanf(file, "players/%s/", str) == 0 || str != path[1] ||
351 sscanf(file, "%*s.") != 0) {
352 error("Illegal restore file name " + file);
353 }
354 break;
355
356 case "obj":
357 case "room":
358 case "std":
359 break;
360
361 default:
362 error("Illegal use of restore_object()");
363 }
364 return ::restore_object(file + ".o");
365 }
366
367 /*
368 * NAME: save_object()
369 * DESCRIPTION: save an object
370 */
save_object(string file)371 static void save_object(string file)
372 {
373 string str, *path;
374
375 ARGCHECK(file, save_object, 1);
376
377 if (this_object() == 0) {
378 return;
379 }
380 if (sscanf(file, "%*s/../") != 0) {
381 error("Illegal save file name " + file);
382 }
383 path = explode(object_name(this_object()), "/");
384 switch (path[0]) {
385 case "players":
386 if (sscanf(file, "players/%s/", str) == 0 || str != path[1] ||
387 sscanf(file, "%*s.") != 0) {
388 error("Illegal save file name " + file);
389 }
390 break;
391
392 case "obj":
393 case "room":
394 case "std":
395 break;
396
397 default:
398 error("Illegal use of save_object()");
399 }
400 ::save_object(file + ".o");
401 }
402
403 /*
404 * NAME: write_bytes()
405 * DESCRIPTION: write bytes to file
406 */
write_bytes(string file,int start,string str)407 static int write_bytes(string file, int start, string str)
408 {
409 int *sizes;
410
411 ARGCHECK(file, write_bytes, 1);
412 ARGCHECK(str, write_bytes, 2);
413
414 file = valid(file, 1);
415 if (file != 0) {
416 if (start == 0) {
417 sizes = ::get_dir(file)[1];
418 if (sizeof(sizes) == 1) {
419 start = -sizes[0];
420 }
421 }
422 return ::write_file(file, str, start);
423 }
424 return 0;
425 }
426
427 /*
428 * NAME: write_file()
429 * DESCRIPTION: write string to file
430 */
write_file(string file,string str)431 static int write_file(string file, string str)
432 {
433 ARGCHECK(file, write_file, 1);
434 file = valid(file, 1);
435 return (file != 0 && ::write_file(file, str));
436 }
437
438 /*
439 * NAME: cat()
440 * DESCRIPTION: show a file
441 */
cat(string file,int first,int num)442 static varargs int cat(string file, int first, int num)
443 {
444 string *lines;
445
446 ARGCHECK(file, cat, 1);
447 file = valid(file, 0);
448 if (file == 0) {
449 return 0;
450 }
451
452 if (num == 0) {
453 num = CAT_LINES + 1;
454 }
455 lines = read_lines(file, first, num);
456 if (lines == 0) {
457 return 0;
458 }
459
460 if (sizeof(lines) <= CAT_LINES + 1) {
461 write(implode(lines, "\n"));
462 } else {
463 write(implode(lines[0 .. CAT_LINES - 1], "\n") +
464 "\n***TRUNCATED***\n");
465 }
466 return 1;
467 }
468
469 /*
470 * NAME: tail()
471 * DESCRIPTION: show the tail of a file
472 */
tail(string file)473 static int tail(string file)
474 {
475 int size, *sizes;
476 string str, *lines;
477
478 ARGCHECK(file, tail, 1);
479 file = valid(file, 0);
480 if (file == 0) {
481 return 0;
482 }
483
484 sizes = ::get_dir(file)[1];
485 if (sizeof(sizes) == 1) {
486 size = TAIL_CHUNK;
487 for (;;) {
488 if (size > sizes[0]) {
489 size = sizes[0];
490 }
491
492 str = ::read_file(file, -size, size);
493 if (str == 0 || strlen(str) != size) {
494 return 0;
495 }
496 lines = explode("\n" + str + "\n", "\n");
497
498 if (sizeof(lines) >= TAIL_LINES + 1 || size == sizes[0]) {
499 if ((size=sizeof(lines)) > TAIL_LINES + 1) {
500 str = implode(lines[size - TAIL_LINES - 1 ..], "\n");
501 } else {
502 sscanf(str, "%*s\n%s", str);
503 }
504 write(str);
505 return 1;
506 }
507 size += TAIL_CHUNK;
508 }
509 }
510 return 0;
511 }
512
513 /*
514 * NAME: editor()
515 * DESCRIPTION: handle an editor command
516 */
editor(string cmd)517 static string editor(string cmd)
518 {
519 string fname;
520
521 fname = explode(object_name(this_object()), "#")[0];
522 if (fname != EDITOR && fname != CINDENT) {
523 error("Illegal call to editor()");
524 }
525 if (cmd == 0) {
526 return ::editor();
527 } else {
528 return ::editor(cmd);
529 }
530 }
531
532 /*
533 * NAME: ed()
534 * DESCRIPTION: start an editor session
535 */
ed(string file,string exit_func)536 static varargs void ed(string file, string exit_func)
537 {
538 object user, editor;
539
540 if (this_player() == 0) {
541 return;
542 }
543 if ((user=interactive(this_object())) == 0) {
544 error("Tried to start an ed session on a non-interactive player");
545 }
546 if (this_player() != this_object()) {
547 error("Illegal start of ed");
548 }
549
550 editor = user->query_editor();
551 if (editor != 0) {
552 error("Tried to start an ed session, when already active");
553 }
554 rlimits (-1; -1) {
555 editor = clone_object(EDITOR);
556 user->set_editor(editor, exit_func);
557 }
558
559 if (file == 0) {
560 editor->edit();
561 } else {
562 editor->edit("e /" + file);
563 }
564 }
565
566 /*
567 * NAME: cindent()
568 * DESCRIPTION: indent an LPC file
569 */
cindent(string file)570 static int cindent(string file)
571 {
572 return clone_object(CINDENT)->indent(file);
573 }
574
575 /*
576 * NAME: ls()
577 * DESCRIPTION: write a directory listing
578 */
ls(string file)579 static int ls(string file)
580 {
581 mixed *dir;
582 string *list, str, dirlist;
583 int *sizes, i, j, sz, max, rows;
584
585 ARGCHECK(file, ls, 1);
586 file = valid(file, 0);
587 if (file == 0) {
588 return 0;
589 }
590
591 i = strlen(file);
592 if (file == "" || file[i - 1] == '/') {
593 file += "*";
594 } else if (i > 1 && file[i - 2 ..] == "/.") {
595 file[i - 1] = '*';
596 }
597 dir = ::get_dir(file);
598 list = dir[0];
599 if (sizeof(list) == 0) {
600 return 0;
601 }
602
603 for (i = 0, sz = sizeof(list); i < sz; i++) {
604 j = strlen(list[i]);
605 if (j > max) {
606 max = j;
607 }
608 }
609 max++;
610 j = 80 / (max + 1);
611 rows = sz / j;
612 if (sz % j > 0) {
613 rows++;
614 }
615
616 dirlist = "";
617 sizes = dir[1];
618 for (i = 0; i < rows; i++) {
619 j = i;
620 for (;;) {
621 str = list[j];
622 if (sizes[j] < 0) {
623 str += "/";
624 }
625 j += rows;
626 if (j >= sz) {
627 dirlist += str + "\n";
628 break;
629 }
630 dirlist += (str + " ")
631 [0 .. max];
632 }
633 }
634 write(dirlist);
635
636 return 1;
637 }
638