1 #pragma strong_types
2 #pragma save_types
3
4 /* obj/simul_efun.c
5 *
6 * The simul-efun object provides functions which can be accessed as
7 * if they were true efuns. This is most useful to protect sensitive
8 * efuns from clumsy fingers, but is also used to simulate functions
9 * which formerly were implemented by the driver.
10 */
11
12 #define MAX_LOG_SIZE 50000
13
14 #define BACKBONE_WIZINFO_SIZE 5
15
16 #define LIVING_NAME 3
17 #define NAME_LIVING 4
18
19 #include "/sys/wizlist.h"
20 #include "/sys/erq.h"
21 #include "/sys/files.h"
22
23 mapping living_name_m, name_living_m;
24 /* Living -> Name and Name -> Living mappings.
25 */
26
27 //---------------------------------------------------------------------------
start_simul_efun()28 void start_simul_efun()
29
30 /* Activate the simul-efun object.
31 */
32
33 {
34 mixed *info;
35
36 if ( !(info = get_extra_wizinfo(0)) )
37 set_extra_wizinfo(0, info = allocate(BACKBONE_WIZINFO_SIZE));
38 if (!(living_name_m = info[LIVING_NAME]))
39 living_name_m = info[LIVING_NAME] = m_allocate(0, 1);
40 if (!(name_living_m = info[NAME_LIVING]))
41 name_living_m = info[NAME_LIVING] = m_allocate(0, 1);
42 }
43
44 //---------------------------------------------------------------------------
ls(string path)45 void ls (string path)
46
47 /* Print the directory listing of <path>, like the unix command.
48 */
49
50 {
51 int max, i, len, tmp;
52 status trunc_flag;
53 mixed *dir;
54 set_this_object(previous_object());
55 dir = get_dir (path, GETDIR_NAMES|GETDIR_SIZES);
56 if (path != "/")
57 path += "/";
58 if (!dir) {
59 write("No such directory.\n");
60 return;
61 }
62 if (sizeof(dir) > 999)
63 {
64 dir = dir[0..998];
65 trunc_flag = 1;
66 }
67 for(i = sizeof(dir); i--; ) {
68 if(dir[i--] == -2)
69 dir[i]+="/";
70 len = strlen(dir[i]);
71 if (len > max)
72 max = len;
73 }
74 ++max;
75 if (max > 79)
76 max = 79;
77 for (i=0; i < sizeof(dir); i+=2) {
78 string name;
79 name = dir[i];
80 tmp = strlen(name);
81 if (len + tmp > 79) {
82 len = 0;
83 write("\n");
84 }
85 write(name);
86 if (len + max > 79) {
87 write("\n");
88 len = 0;
89 } else {
90 write(" "[80-max+tmp..]);
91 len += max;
92 }
93 }
94 write("\n");
95 if (trunc_flag) write("***TRUNCATED***\n");
96 }
97
98 //---------------------------------------------------------------------------
create_wizard(string owner,string domain)99 string create_wizard(string owner, string domain)
100 {
101 mixed result;
102
103 set_this_object(previous_object());
104 result =
105 (mixed)__MASTER_OBJECT__->master_create_wizard(owner, domain, previous_object());
106 if (stringp(result)) return result;
107 return 0;
108 }
109
110 //---------------------------------------------------------------------------
log_file(string file,string str)111 void log_file(string file,string str)
112 {
113 string file_name;
114 int *st;
115
116 file_name = "/log/" + file;
117 #ifdef COMPAT_FLAG
118 if (sizeof(regexp(({file}), "/")) || file[0] == '.' || strlen(file) > 30 )
119 {
120 write("Illegal file name to log_file("+file+")\n");
121 return;
122 }
123 #endif
124 if ( sizeof(st = get_dir(file_name,2) ) && st[0] > MAX_LOG_SIZE) {
125 catch(rename(file_name, file_name + ".old")); /* No panic if failure */
126 }
127 set_this_object(previous_object());
128 write_file(file_name, str);
129 }
130
131 //---------------------------------------------------------------------------
localcmd()132 void localcmd()
133 {
134 string *verbs;
135 int i,j;
136
137 verbs = query_actions(this_player());
138 for (i=0, j = sizeof(verbs); --j >= 0; i++) {
139 write(verbs[i]+" ");
140 }
141 write("\n");
142 }
143
144 //---------------------------------------------------------------------------
unique_array(mixed * arr,string func,mixed skipnum)145 mixed *unique_array(mixed *arr,string func,mixed skipnum)
146 {
147 mixed *al, last;
148 mapping m;
149 int i, j, k, *ordinals;
150
151 if (sizeof(arr) < 32)
152 return efun::unique_array(arr, func, skipnum);
153 for (ordinals = allocate(i = sizeof(arr)); i--; )
154 ordinals[i] = i;
155 m = mkmapping(map_objects(arr, func), ordinals, arr);
156 al = m_indices(m);
157 ordinals = m_values(m, 0);
158 arr = m_values(m, 1);
159 if (k = i = sizeof(al)) {
160 for (last = al[j = --i]; i--; ) {
161 if (al[i] != last) {
162 if (last != skipnum) {
163 arr[--k] = arr[i+1..j];
164 ordinals[k] = ordinals[j];
165 }
166 last = al[j = i];
167 }
168 }
169 if (last != skipnum) {
170 arr[--k] = arr[0..j];
171 ordinals[k] = ordinals[j];
172 }
173 }
174 return m_values(mkmapping(ordinals[k..], arr[k..]),0);
175 }
176
177 //---------------------------------------------------------------------------
snoop(mixed snoopee)178 varargs mixed snoop(mixed snoopee)
179 {
180 int result;
181
182 if (snoopee && query_snoop(snoopee)) {
183 write("Busy.\n");
184 return 0;
185 }
186 result = snoopee ? efun::snoop(this_player(), snoopee)
187 : efun::snoop(this_player());
188 switch (result) {
189 case -1:
190 write("Busy.\n");
191 break;
192 case 0:
193 write("Failed.\n");
194 break;
195 case 1:
196 write("Ok.\n");
197 break;
198 }
199 if (result > 0) return snoopee;
200 }
201
202 //---------------------------------------------------------------------------
notify_fail(mixed message)203 void notify_fail(mixed message)
204 {
205 if ( !(stringp(message) && strstr(message, "@@") < 0) ) {
206 efun::notify_fail(message);
207 return;
208 }
209 efun::notify_fail(
210 funcall(
211 bind_lambda(#'lambda, previous_object()),
212 0, ({#'process_string, message})
213 )
214 );
215 }
216
217 //---------------------------------------------------------------------------
218 string version() {
219 return __VERSION__;
220 }
221
222 //---------------------------------------------------------------------------
223 string query_host_name() {
224 return __HOST_NAME__;
225 }
226
227 //---------------------------------------------------------------------------
228 nomask void set_environment() {}
229
230 nomask void set_this_player() {}
231
232 //---------------------------------------------------------------------------
233 varargs void add_worth(int value, object ob)
234 {
235 mixed old;
236 #ifdef __COMPAT_MODE__
237 switch (explode(object_name(previous_object()), "/")[0]) {
238 #else
239 switch (explode(object_name(previous_object()), "/")[1]) {
240 #endif
241 default:
242 raise_error("Illegal call of add_worth.\n");
243 case "obj":
244 case "std":
245 case "room":
246 }
247 if (!ob) {
248 if ( !(ob = previous_object(1)) )
249 return;
250 }
251 if (intp(old = get_extra_wizinfo(ob)))
252 set_extra_wizinfo(ob, old + value);
253 }
254
255 //---------------------------------------------------------------------------
256 varargs void wizlist(string name)
257 {
258 int i, pos, total_cmd;
259 int *cmds;
260 mixed *a;
261 mixed *b;
262
263 if (!name) {
264 name = this_player()->query_real_name();
265 if (!name)
266 {
267 write("Need to provide a name or 'ALL' to the wizlist function.\n");
268 return;
269 }
270 }
271 a = transpose_array(wizlist_info());
272 cmds = a[WL_COMMANDS];
273 a[WL_COMMANDS] = a[0];
274 a[0] = cmds;
275
276 a = unmkmapping(apply(#'mkmapping, a));
277 cmds = a[0];
278 a[0] = a[WL_COMMANDS];
279 a[WL_COMMANDS] = cmds;
280
281 if ((pos = member(a[WL_NAME], name)) < 0 && name != "ALL")
282 {
283 write("No wizlist info for '"+name+"' found.\n");
284 return;
285 }
286 b = allocate(sizeof(cmds));
287 for (i = sizeof(cmds); i;) {
288 b[<i] = i;
289 total_cmd += cmds[--i];
290 }
291 a = transpose_array(a + ({b}) );
292 if (name != "ALL") {
293 if (pos + 18 < sizeof(cmds)) {
294 a = a[pos-2..pos+2]+a[<15..];
295 } else if (pos < sizeof(cmds) - 13) {
296 a = a[pos-2..];
297 } else {
298 a = a[<15..];
299 }
300 }
301 write("\nWizard top score list\n\n");
302 if (total_cmd == 0)
303 total_cmd = 1;
304 for (i = sizeof(a); i; ) {
305 b = a[<i--];
306 if (b[WL_GIGACOST] > 1000)
307 printf("%-15s %5d %2d%% (%d)\t[%d%4dk,%5d] %6d %d\n",
308 b[WL_NAME], b[WL_COMMANDS],
309 b[WL_COMMANDS] * 100 / total_cmd, b[<1],
310 b[WL_GIGACOST] / 1000,
311 b[WL_COST] / 1000 + (b[WL_GIGACOST] % 1000) * 1000000000,
312 b[WL_HEART_BEATS], b[WL_EXTRA], b[WL_ARRAY_TOTAL]
313 );
314 else
315 printf("%-15s %5d %2d%% (%d)\t[%4dk,%5d] %6d %d\n",
316 b[WL_NAME], b[WL_COMMANDS],
317 b[WL_COMMANDS] * 100 / total_cmd, b[<1],
318 b[WL_COST] / 1000 + (b[WL_GIGACOST] % 1000) * 1000000000,
319 b[WL_HEART_BEATS], b[WL_EXTRA], b[WL_ARRAY_TOTAL]
320 );
321 }
322 printf("\nTotal %7d (%d)\n\n", total_cmd, sizeof(cmds));
323 }
324
325 //---------------------------------------------------------------------------
326 void shout(string s)
327 {
328 filter(users(), lambda(({'u}),({#'&&,
329 ({#'environment, 'u}),
330 ({#'!=, 'u, ({#'this_player})}),
331 ({#'tell_object, 'u, to_string(s)})
332 })));
333 }
334
335 //---------------------------------------------------------------------------
336 void set_living_name(string name)
337 {
338 string old;
339 mixed a;
340 int i;
341
342 if (old = living_name_m[previous_object()]) {
343 if (pointerp(a = name_living_m[old])) {
344 a[member(a, previous_object())] = 0;
345 } else {
346 efun::m_delete(name_living_m, old);
347 }
348 }
349 living_name_m[previous_object()] = name;
350 if (a = name_living_m[name]) {
351 if (!pointerp(a)) {
352 name_living_m[name] = ({a, previous_object()});
353 return;
354 }
355 /* Try to reallocate entry from destructed object */
356 if ((i = member(a, 0)) >= 0) {
357 a[i] = previous_object();
358 return;
359 }
360 name_living_m[name] = a + ({previous_object()});
361 return;
362 }
363 name_living_m[name] = previous_object();
364 }
365
366 //---------------------------------------------------------------------------
367 object find_living(string name)
368 {
369 mixed *a, r;
370 int i;
371
372 if (pointerp(r = name_living_m[name])) {
373 if ( !living(r = (a = r)[0])) {
374 for (i = sizeof(a); --i;) {
375 if (living(a[<i])) {
376 r = a[<i];
377 a[<i] = a[0];
378 return a[0] = r;
379 }
380 }
381 }
382 return r;
383 }
384 return living(r) && r;
385 }
386
387 //---------------------------------------------------------------------------
388 object find_player(string name)
389 {
390 mixed *a, r;
391 int i;
392
393 if (pointerp(r = name_living_m[name])) {
394 if ( !(r = (a = r)[0]) || !query_once_interactive(r)) {
395 for (i = sizeof(a); --i;) {
396 if (a[<i] && query_once_interactive(a[<i])) {
397 r = a[<i];
398 a[<i] = a[0];
399 return a[0] = r;
400 }
401 }
402 return 0;
403 }
404 return r;
405 }
406 return r && query_once_interactive(r) && r;
407 }
408
409 /*===========================================================================
410 * The following functions provide the necessary compatibility of this
411 * compat-mode mudlib with a plain driver.
412 * Just the parse_command() efun is not simulated.
413 */
414
415 #ifndef __COMPAT_MODE__
416 //---------------------------------------------------------------------------
417 string function_exists (string str, object ob)
418 {
419 string rc;
420
421 rc = efun::function_exists(str, ob);
422 return stringp(rc) ? rc[1..] : 0;
423 }
424
425 //---------------------------------------------------------------------------
426 string object_name(object ob)
427 {
428 string rc;
429
430 rc = efun::object_name(ob);
431 return stringp(rc) ? rc[1..] : 0;
432 }
433
434 //---------------------------------------------------------------------------
435 string program_name(object ob)
436 {
437 string rc;
438
439 rc = efun::program_name(ob);
440 return stringp(rc) ? rc[1..] : 0;
441 }
442
443 //---------------------------------------------------------------------------
444 string* inherit_list(object ob)
445 {
446 string *rc;
447 int i;
448
449 rc = efun::inherit_list(ob);
450 for (i = sizeof(rc); i-- > 0; )
451 rc[i] = rc[i][1..];
452 return rc;
453 }
454
455 //---------------------------------------------------------------------------
456 string to_string(mixed arg)
457 {
458 string rc;
459
460 rc = efun::to_string(arg);
461 return objectp(arg) ? rc[1..] : rc;
462 }
463
464 //---------------------------------------------------------------------------
465 string creator(object ob)
466 {
467 return getuid(ob);
468 }
469
470 //---------------------------------------------------------------------------
471 varargs void add_action(string fun, string cmd, int flag)
472 {
473 if (fun == "exit")
474 raise_error("Illegal to define a command to the exit() function.\n");
475
476 efun::set_this_object(previous_object());
477 if (cmd)
478 efun::add_action(fun, cmd, flag);
479 }
480
481 //---------------------------------------------------------------------------
482 object present_clone (mixed obj, object env)
483 {
484 if (stringp(obj) && '/' != obj[0])
485 obj = "/"+obj;
486 return efun::present_clone(obj, env);
487 }
488
489 //---------------------------------------------------------------------------
490 #endif /* __COMPAT_MODE__ */
491
492 #if !__EFUN_DEFINED__(present)
493 //---------------------------------------------------------------------------
494 varargs object present(mixed ob, object env)
495 {
496 int specific, num, i;
497 object found;
498 string str;
499
500 if (!env)
501 {
502 env = previous_object();
503 specific = 0;
504 }
505 else
506 specific = 1;
507
508 if (objectp(ob))
509 {
510 /* Quick check: is ob there or not? */
511
512 if (specific)
513 return environment(ob) == env ? ob : 0;
514 if (environment(ob) == env
515 || (environment(env) && environment(ob) == environment(env))
516 )
517 return ob;
518 return 0;
519 }
520
521 /* Search by name. Prepare the search parameters */
522 if (2 != sscanf(ob, "%s %d", str, num))
523 {
524 num = 1;
525 str = ob;
526 }
527
528 /* First, search in env by name */
529 for (found = first_inventory(env), i = 0
530 ; found
531 ; found = next_inventory(env))
532 {
533 if (found->id(str) && ++i == num)
534 break;
535 if (!found) /* may happen */
536 break;
537 }
538
539 if (found || specific)
540 return found;
541
542 /* If not found, search in environment(env) by name */
543 env = environment(env);
544 if (!env)
545 return 0;
546 if (env->id(ob))
547 return env;
548 if (!env) /* the id() may have destructed env */
549 return 0;
550
551 for (found = first_inventory(env), i = 0
552 ; found
553 ; found = next_inventory(env))
554 {
555 if (found->id(str) && ++i == num)
556 break;
557 if (!found) /* may happen */
558 break;
559 }
560
561 return found;
562 }
563
564 #endif /* !efun_defined(present) */
565
566 #if !__EFUN_DEFINED__(transfer)
567 //---------------------------------------------------------------------------
568 /*
569 * Transfer an object from an object to an object.
570 * Call add_weight(), drop(), get(), prevent_insert(), add_weight(),
571 * and can_put_and_get() where needed.
572 * Return 0 on success, and special code on failure:
573 *
574 * 1: To heavy for destination.
575 * 2: Can't be dropped.
576 * 3: Can't take it out of it's container.
577 * 4: The object can't be inserted into bags etc.
578 * 5: The destination doesn't allow insertions of objects.
579 * 6: The object can't be picked up.
580 */
581 int transfer(object item, object dest)
582 {
583 int weight;
584 object from;
585
586 efun::set_this_object(previous_object());
587
588 weight = item->query_weight();
589 if (!item)
590 return 3;
591
592 from = environment(item);
593 if (from)
594 {
595 /*
596 * If the original place of the object is a living object,
597 * then we must call drop() to check that the object can be dropped.
598 */
599 if (living(from))
600 {
601 if (item->drop() || !item)
602 return 2;
603 }
604 /*
605 * If 'from' is not a room and not a player, check that we may
606 * remove things out of it.
607 */
608 else if (environment(from))
609 {
610 if (!from->can_put_and_get() || !from)
611 return 3;
612 }
613 }
614
615 /*
616 * If the destination is not a room, and not a player,
617 * Then we must test 'prevent_insert', and 'can_put_and_get'.
618 */
619 if (environment(dest) && !living(dest))
620 {
621 if (item->prevent_insert())
622 return 4;
623 if (!dest->can_put_and_get() || !dest)
624 return 5;
625 }
626
627 if (living(dest))
628 {
629 if (!item->get() || !item)
630 return 6;
631 }
632
633 /*
634 * If it is not a room, correct the total weight in the destination.
635 */
636 if (environment(dest) && weight)
637 {
638 if (!dest->add_weight(weight) || !dest)
639 return 1;
640 }
641
642 /*
643 * If it is not a room, correct the weight in the 'from' object.
644 */
645 if (from && environment(from) && weight)
646 {
647 from->add_weight(-weight);
648 }
649
650 move_object(item, dest);
651
652 return 0;
653 }
654
655 #endif /* !efun_define(transfer) */
656
657 #if !__EFUN_DEFINED__(extract)
658 //---------------------------------------------------------------------------
659 mixed extract (mixed data, varargs mixed*from_to)
660
661 {
662 int from, to;
663
664 if (!stringp(data) && !pointerp(data))
665 {
666 raise_error("Illegal type for extract(): must be string or array.\n");
667 return 0;
668 }
669
670 switch(sizeof(from_to))
671 {
672 case 0: return data;
673 case 1:
674 if (!intp(from_to[0]))
675 {
676 raise_error("Illegal 'from' index for extract(): must be a number.\n");
677 return 0;
678 }
679 from = from_to[0];
680 if (from >= 0)
681 return data[from..];
682 return data[<-from..];
683 case 2:
684 if (!intp(from_to[0]) || !intp(from_to[1]))
685 {
686 raise_error("Illegal index for extract(): must be a number.\n");
687 return 0;
688 }
689 from = from_to[0];
690 to = from_to[1];
691 if (from >= 0)
692 {
693 if (to >= 0)
694 return data[from..to];
695 return data[<from..<-to];
696 }
697 if (to >= 0)
698 return data[<-from..to];
699 return data[<from..<-to];
700 }
701
702 raise_error("Illegal number of arguments for extract().\n");
703 return 0;
704 }
705
706 #endif /* !efun_defined(extract) */
707
708 /*************************************************************************/
709