|
|
1.1 ! root 1: // cmd.c -- Quake script command processing module ! 2: ! 3: #include "quakedef.h" ! 4: ! 5: void Cmd_ForwardToServer (void); ! 6: ! 7: typedef struct cmdalias_s ! 8: { ! 9: struct cmdalias_s *next; ! 10: char *name; ! 11: char *value; ! 12: } cmdalias_t; ! 13: ! 14: cmdalias_t *cmd_alias; ! 15: ! 16: int trashtest; ! 17: int *trashspot; ! 18: ! 19: qboolean cmd_wait; ! 20: ! 21: //============================================================================= ! 22: ! 23: /* ! 24: ============ ! 25: Cmd_Wait_f ! 26: ! 27: Causes execution of the remainder of the command buffer to be delayed until ! 28: next frame. This allows commands like: ! 29: bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" ! 30: ============ ! 31: */ ! 32: void Cmd_Wait_f (void) ! 33: { ! 34: cmd_wait = true; ! 35: } ! 36: ! 37: /* ! 38: ============================================================================= ! 39: ! 40: COMMAND BUFFER ! 41: ! 42: ============================================================================= ! 43: */ ! 44: ! 45: sizebuf_t cmd_text; ! 46: ! 47: /* ! 48: ============ ! 49: Cbuf_Init ! 50: ============ ! 51: */ ! 52: void Cbuf_Init (void) ! 53: { ! 54: SZ_Alloc (&cmd_text, 8192); // space for commands and script files ! 55: } ! 56: ! 57: /* ! 58: ============ ! 59: Cbuf_AddText ! 60: ! 61: Adds command text at the end of the buffer ! 62: ============ ! 63: */ ! 64: void Cbuf_AddText (char *text) ! 65: { ! 66: int l; ! 67: ! 68: l = Q_strlen (text); ! 69: ! 70: if (cmd_text.cursize + l >= cmd_text.maxsize) ! 71: { ! 72: Con_Printf ("Cbuf_AddText: overflow\n"); ! 73: return; ! 74: } ! 75: SZ_Write (&cmd_text, text, Q_strlen (text)); ! 76: } ! 77: ! 78: ! 79: /* ! 80: ============ ! 81: Cbuf_InsertText ! 82: ! 83: Adds command text immediately after the current command ! 84: Adds a \n to the text ! 85: FIXME: actually change the command buffer to do less copying ! 86: ============ ! 87: */ ! 88: void Cbuf_InsertText (char *text) ! 89: { ! 90: char *temp; ! 91: int templen; ! 92: ! 93: // copy off any commands still remaining in the exec buffer ! 94: templen = cmd_text.cursize; ! 95: if (templen) ! 96: { ! 97: temp = Z_Malloc (templen); ! 98: Q_memcpy (temp, cmd_text.data, templen); ! 99: SZ_Clear (&cmd_text); ! 100: } ! 101: else ! 102: temp = NULL; // shut up compiler ! 103: ! 104: // add the entire text of the file ! 105: Cbuf_AddText (text); ! 106: ! 107: // add the copied off data ! 108: if (templen) ! 109: { ! 110: SZ_Write (&cmd_text, temp, templen); ! 111: Z_Free (temp); ! 112: } ! 113: } ! 114: ! 115: /* ! 116: ============ ! 117: Cbuf_Execute ! 118: ============ ! 119: */ ! 120: void Cbuf_Execute (void) ! 121: { ! 122: int i; ! 123: char *text; ! 124: char line[1024]; ! 125: int quotes; ! 126: ! 127: while (cmd_text.cursize) ! 128: { ! 129: // find a \n or ; line break ! 130: text = (char *)cmd_text.data; ! 131: ! 132: quotes = 0; ! 133: for (i=0 ; i< cmd_text.cursize ; i++) ! 134: { ! 135: if (text[i] == '"') ! 136: quotes++; ! 137: if ( !(quotes&1) && text[i] == ';') ! 138: break; // don't break if inside a quoted string ! 139: if (text[i] == '\n') ! 140: break; ! 141: } ! 142: ! 143: ! 144: memcpy (line, text, i); ! 145: line[i] = 0; ! 146: ! 147: // delete the text from the command buffer and move remaining commands down ! 148: // this is necessary because commands (exec, alias) can insert data at the ! 149: // beginning of the text buffer ! 150: ! 151: if (i == cmd_text.cursize) ! 152: cmd_text.cursize = 0; ! 153: else ! 154: { ! 155: i++; ! 156: cmd_text.cursize -= i; ! 157: Q_memcpy (text, text+i, cmd_text.cursize); ! 158: } ! 159: ! 160: // execute the command line ! 161: Cmd_ExecuteString (line, src_command); ! 162: ! 163: if (cmd_wait) ! 164: { // skip out while text still remains in buffer, leaving it ! 165: // for next frame ! 166: cmd_wait = false; ! 167: break; ! 168: } ! 169: } ! 170: } ! 171: ! 172: /* ! 173: ============================================================================== ! 174: ! 175: SCRIPT COMMANDS ! 176: ! 177: ============================================================================== ! 178: */ ! 179: ! 180: /* ! 181: =============== ! 182: Cmd_StuffCmds_f ! 183: ! 184: Adds command line parameters as script statements ! 185: Commands lead with a +, and continue until a - or another + ! 186: quake +prog jctest.qp +cmd amlev1 ! 187: quake -nosound +cmd amlev1 ! 188: =============== ! 189: */ ! 190: void Cmd_StuffCmds_f (void) ! 191: { ! 192: int i, j; ! 193: int s; ! 194: char *text, *build, c; ! 195: ! 196: if (Cmd_Argc () != 1) ! 197: { ! 198: Con_Printf ("stuffcmds : execute command line parameters\n"); ! 199: return; ! 200: } ! 201: ! 202: // build the combined string to parse from ! 203: s = 0; ! 204: for (i=1 ; i<com_argc ; i++) ! 205: { ! 206: if (!com_argv[i]) ! 207: continue; // NEXTSTEP nulls out -NXHost ! 208: s += Q_strlen (com_argv[i]) + 1; ! 209: } ! 210: if (!s) ! 211: return; ! 212: ! 213: text = Z_Malloc (s+1); ! 214: text[0] = 0; ! 215: for (i=1 ; i<com_argc ; i++) ! 216: { ! 217: if (!com_argv[i]) ! 218: continue; // NEXTSTEP nulls out -NXHost ! 219: Q_strcat (text,com_argv[i]); ! 220: if (i != com_argc-1) ! 221: Q_strcat (text, " "); ! 222: } ! 223: ! 224: // pull out the commands ! 225: build = Z_Malloc (s+1); ! 226: build[0] = 0; ! 227: ! 228: for (i=0 ; i<s-1 ; i++) ! 229: { ! 230: if (text[i] == '+') ! 231: { ! 232: i++; ! 233: ! 234: for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++) ! 235: ; ! 236: ! 237: c = text[j]; ! 238: text[j] = 0; ! 239: ! 240: Q_strcat (build, text+i); ! 241: Q_strcat (build, "\n"); ! 242: text[j] = c; ! 243: i = j-1; ! 244: } ! 245: } ! 246: ! 247: if (build[0]) ! 248: Cbuf_InsertText (build); ! 249: ! 250: Z_Free (text); ! 251: Z_Free (build); ! 252: } ! 253: ! 254: ! 255: /* ! 256: =============== ! 257: Cmd_Exec_f ! 258: =============== ! 259: */ ! 260: void Cmd_Exec_f (void) ! 261: { ! 262: char *f; ! 263: int mark; ! 264: ! 265: if (Cmd_Argc () != 2) ! 266: { ! 267: Con_Printf ("exec <filename> : execute a script file\n"); ! 268: return; ! 269: } ! 270: ! 271: mark = Hunk_LowMark (); ! 272: f = (char *)COM_LoadHunkFile (Cmd_Argv(1)); ! 273: if (!f) ! 274: { ! 275: Con_Printf ("couldn't exec %s\n",Cmd_Argv(1)); ! 276: return; ! 277: } ! 278: Con_Printf ("execing %s\n",Cmd_Argv(1)); ! 279: ! 280: Cbuf_InsertText (f); ! 281: Hunk_FreeToLowMark (mark); ! 282: } ! 283: ! 284: ! 285: /* ! 286: =============== ! 287: Cmd_Echo_f ! 288: ! 289: Just prints the rest of the line to the console ! 290: =============== ! 291: */ ! 292: void Cmd_Echo_f (void) ! 293: { ! 294: int i; ! 295: ! 296: for (i=1 ; i<Cmd_Argc() ; i++) ! 297: Con_Printf ("%s ",Cmd_Argv(i)); ! 298: Con_Printf ("\n"); ! 299: } ! 300: ! 301: /* ! 302: =============== ! 303: Cmd_Alias_f ! 304: ! 305: Creates a new command that executes a command string (possibly ; seperated) ! 306: =============== ! 307: */ ! 308: ! 309: char *CopyString (char *in) ! 310: { ! 311: char *out; ! 312: ! 313: out = Z_Malloc (strlen(in)+1); ! 314: strcpy (out, in); ! 315: return out; ! 316: } ! 317: ! 318: void Cmd_Alias_f (void) ! 319: { ! 320: cmdalias_t *a; ! 321: char cmd[1024]; ! 322: int i, c; ! 323: ! 324: a = Z_Malloc (sizeof(cmdalias_t)); ! 325: a->next = cmd_alias; ! 326: cmd_alias = a; ! 327: ! 328: a->name = CopyString (Cmd_Argv(1)); ! 329: ! 330: // copy the rest of the command line ! 331: cmd[0] = 0; // start out with a null string ! 332: c = Cmd_Argc(); ! 333: for (i=2 ; i< c ; i++) ! 334: { ! 335: strcat (cmd, Cmd_Argv(i)); ! 336: if (i != c) ! 337: strcat (cmd, " "); ! 338: } ! 339: strcat (cmd, "\n"); ! 340: ! 341: a->value = CopyString (cmd); ! 342: } ! 343: ! 344: /* ! 345: ============================================================================= ! 346: ! 347: COMMAND EXECUTION ! 348: ! 349: ============================================================================= ! 350: */ ! 351: ! 352: typedef struct cmd_function_s ! 353: { ! 354: struct cmd_function_s *next; ! 355: char *name; ! 356: xcommand_t function; ! 357: } cmd_function_t; ! 358: ! 359: ! 360: #define MAX_ARGS 80 ! 361: ! 362: static int cmd_argc; ! 363: static char *cmd_argv[MAX_ARGS]; ! 364: static char *cmd_null_string = ""; ! 365: static char *cmd_args = NULL; ! 366: ! 367: cmd_source_t cmd_source; ! 368: ! 369: ! 370: static cmd_function_t *cmd_functions; // possible commands to execute ! 371: ! 372: /* ! 373: ============ ! 374: Cmd_Init ! 375: ============ ! 376: */ ! 377: void Cmd_Init (void) ! 378: { ! 379: // ! 380: // register our commands ! 381: // ! 382: Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f); ! 383: Cmd_AddCommand ("exec",Cmd_Exec_f); ! 384: Cmd_AddCommand ("echo",Cmd_Echo_f); ! 385: Cmd_AddCommand ("alias",Cmd_Alias_f); ! 386: Cmd_AddCommand ("cmd", Cmd_ForwardToServer); ! 387: Cmd_AddCommand ("wait", Cmd_Wait_f); ! 388: } ! 389: ! 390: /* ! 391: ============ ! 392: Cmd_Argc ! 393: ============ ! 394: */ ! 395: int Cmd_Argc (void) ! 396: { ! 397: return cmd_argc; ! 398: } ! 399: ! 400: /* ! 401: ============ ! 402: Cmd_Argv ! 403: ============ ! 404: */ ! 405: char *Cmd_Argv (int arg) ! 406: { ! 407: if ( (unsigned)arg >= cmd_argc ) ! 408: return cmd_null_string; ! 409: return cmd_argv[arg]; ! 410: } ! 411: ! 412: /* ! 413: ============ ! 414: Cmd_Args ! 415: ============ ! 416: */ ! 417: char *Cmd_Args (void) ! 418: { ! 419: return cmd_args; ! 420: } ! 421: ! 422: ! 423: /* ! 424: ============ ! 425: Cmd_TokenizeString ! 426: ! 427: Parses the given string into command line tokens. ! 428: ============ ! 429: */ ! 430: void Cmd_TokenizeString (char *text) ! 431: { ! 432: int i; ! 433: ! 434: // clear the args from the last string ! 435: for (i=0 ; i<cmd_argc ; i++) ! 436: Z_Free (cmd_argv[i]); ! 437: ! 438: cmd_argc = 0; ! 439: cmd_args = NULL; ! 440: ! 441: while (1) ! 442: { ! 443: // skip whitespace up to a /n ! 444: while (*text && *text <= ' ' && *text != '\n') ! 445: { ! 446: text++; ! 447: } ! 448: ! 449: if (*text == '\n') ! 450: { // a newline seperates commands in the buffer ! 451: text++; ! 452: break; ! 453: } ! 454: ! 455: if (!*text) ! 456: return; ! 457: ! 458: if (cmd_argc == 1) ! 459: cmd_args = text; ! 460: ! 461: text = COM_Parse (text); ! 462: if (!text) ! 463: return; ! 464: ! 465: if (cmd_argc < MAX_ARGS) ! 466: { ! 467: cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1); ! 468: Q_strcpy (cmd_argv[cmd_argc], com_token); ! 469: cmd_argc++; ! 470: } ! 471: } ! 472: ! 473: } ! 474: ! 475: ! 476: /* ! 477: ============ ! 478: Cmd_AddCommand ! 479: ============ ! 480: */ ! 481: void Cmd_AddCommand (char *cmd_name, xcommand_t function) ! 482: { ! 483: cmd_function_t *cmd; ! 484: ! 485: if (host_initialized) // because hunk allocation would get stomped ! 486: Sys_Error ("Cmd_AddCommand after host_initialized"); ! 487: ! 488: // fail if the command is a variable name ! 489: if (Cvar_VariableString(cmd_name)[0]) ! 490: { ! 491: Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name); ! 492: return; ! 493: } ! 494: ! 495: // fail if the command already exists ! 496: for (cmd=cmd_functions ; cmd ; cmd=cmd->next) ! 497: { ! 498: if (!Q_strcmp (cmd_name, cmd->name)) ! 499: { ! 500: Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); ! 501: return; ! 502: } ! 503: } ! 504: ! 505: cmd = Hunk_Alloc (sizeof(cmd_function_t)); ! 506: cmd->name = cmd_name; ! 507: cmd->function = function; ! 508: cmd->next = cmd_functions; ! 509: cmd_functions = cmd; ! 510: } ! 511: ! 512: /* ! 513: ============ ! 514: Cmd_Exists ! 515: ============ ! 516: */ ! 517: qboolean Cmd_Exists (char *cmd_name) ! 518: { ! 519: cmd_function_t *cmd; ! 520: ! 521: for (cmd=cmd_functions ; cmd ; cmd=cmd->next) ! 522: { ! 523: if (!Q_strcmp (cmd_name,cmd->name)) ! 524: return true; ! 525: } ! 526: ! 527: return false; ! 528: } ! 529: ! 530: ! 531: ! 532: /* ! 533: ============ ! 534: Cmd_CompleteCommand ! 535: ============ ! 536: */ ! 537: char *Cmd_CompleteCommand (char *partial) ! 538: { ! 539: cmd_function_t *cmd; ! 540: int len; ! 541: ! 542: len = Q_strlen(partial); ! 543: ! 544: if (!len) ! 545: return NULL; ! 546: ! 547: // check functions ! 548: for (cmd=cmd_functions ; cmd ; cmd=cmd->next) ! 549: if (!Q_strncmp (partial,cmd->name, len)) ! 550: return cmd->name; ! 551: ! 552: return NULL; ! 553: } ! 554: ! 555: /* ! 556: ============ ! 557: Cmd_ExecuteString ! 558: ! 559: A complete command line has been parsed, so try to execute it ! 560: FIXME: lookupnoadd the token to speed search? ! 561: ============ ! 562: */ ! 563: void Cmd_ExecuteString (char *text, cmd_source_t src) ! 564: { ! 565: cmd_function_t *cmd; ! 566: cmdalias_t *a; ! 567: ! 568: cmd_source = src; ! 569: Cmd_TokenizeString (text); ! 570: ! 571: // execute the command line ! 572: if (!Cmd_Argc()) ! 573: return; // no tokens ! 574: ! 575: // check functions ! 576: for (cmd=cmd_functions ; cmd ; cmd=cmd->next) ! 577: { ! 578: if (!Q_strcasecmp (cmd_argv[0],cmd->name)) ! 579: { ! 580: cmd->function (); ! 581: return; ! 582: } ! 583: } ! 584: ! 585: // check alias ! 586: for (a=cmd_alias ; a ; a=a->next) ! 587: { ! 588: if (!Q_strcasecmp (cmd_argv[0], a->name)) ! 589: { ! 590: Cbuf_InsertText (a->value); ! 591: return; ! 592: } ! 593: } ! 594: ! 595: // check cvars ! 596: if (!Cvar_Command ()) ! 597: Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0)); ! 598: ! 599: } ! 600: ! 601: ! 602: /* ! 603: =================== ! 604: Cmd_ForwardToServer ! 605: ! 606: Sends the entire command line over to the server ! 607: =================== ! 608: */ ! 609: void Cmd_ForwardToServer (void) ! 610: { ! 611: if (cls.state != ca_connected) ! 612: { ! 613: Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); ! 614: return; ! 615: } ! 616: ! 617: if (cls.demoplayback) ! 618: return; // not really connected ! 619: ! 620: MSG_WriteByte (&cls.message, clc_stringcmd); ! 621: if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0) ! 622: { ! 623: SZ_Print (&cls.message, Cmd_Argv(0)); ! 624: SZ_Print (&cls.message, " "); ! 625: } ! 626: if (Cmd_Argc() > 1) ! 627: SZ_Print (&cls.message, Cmd_Args()); ! 628: else ! 629: SZ_Print (&cls.message, "\n"); ! 630: } ! 631: ! 632: ! 633: /* ! 634: ================ ! 635: Cmd_CheckParm ! 636: ! 637: Returns the position (1 to argc-1) in the command's argument list ! 638: where the given parameter apears, or 0 if not present ! 639: ================ ! 640: */ ! 641: ! 642: int Cmd_CheckParm (char *parm) ! 643: { ! 644: int i; ! 645: ! 646: if (!parm) ! 647: Sys_Error ("Cmd_CheckParm: NULL"); ! 648: ! 649: for (i = 1; i < Cmd_Argc (); i++) ! 650: if (! Q_strcasecmp (parm, Cmd_Argv (i))) ! 651: return i; ! 652: ! 653: return 0; ! 654: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.