(root)/
Python-3.12.0/
Modules/
main.c
       1  /* Python interpreter main program */
       2  
       3  #include "Python.h"
       4  #include "pycore_call.h"          // _PyObject_CallNoArgs()
       5  #include "pycore_initconfig.h"    // _PyArgv
       6  #include "pycore_interp.h"        // _PyInterpreterState.sysdict
       7  #include "pycore_pathconfig.h"    // _PyPathConfig_ComputeSysPath0()
       8  #include "pycore_pylifecycle.h"   // _Py_PreInitializeFromPyArgv()
       9  #include "pycore_pystate.h"       // _PyInterpreterState_GET()
      10  
      11  /* Includes for exit_sigint() */
      12  #include <stdio.h>                // perror()
      13  #ifdef HAVE_SIGNAL_H
      14  #  include <signal.h>             // SIGINT
      15  #endif
      16  #if defined(HAVE_GETPID) && defined(HAVE_UNISTD_H)
      17  #  include <unistd.h>             // getpid()
      18  #endif
      19  #ifdef MS_WINDOWS
      20  #  include <windows.h>            // STATUS_CONTROL_C_EXIT
      21  #endif
      22  /* End of includes for exit_sigint() */
      23  
      24  #define COPYRIGHT \
      25      "Type \"help\", \"copyright\", \"credits\" or \"license\" " \
      26      "for more information."
      27  
      28  #ifdef __cplusplus
      29  extern "C" {
      30  #endif
      31  
      32  /* --- pymain_init() ---------------------------------------------- */
      33  
      34  static PyStatus
      35  pymain_init(const _PyArgv *args)
      36  {
      37      PyStatus status;
      38  
      39      status = _PyRuntime_Initialize();
      40      if (_PyStatus_EXCEPTION(status)) {
      41          return status;
      42      }
      43  
      44      PyPreConfig preconfig;
      45      PyPreConfig_InitPythonConfig(&preconfig);
      46  
      47      status = _Py_PreInitializeFromPyArgv(&preconfig, args);
      48      if (_PyStatus_EXCEPTION(status)) {
      49          return status;
      50      }
      51  
      52      PyConfig config;
      53      PyConfig_InitPythonConfig(&config);
      54  
      55      /* pass NULL as the config: config is read from command line arguments,
      56         environment variables, configuration files */
      57      if (args->use_bytes_argv) {
      58          status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv);
      59      }
      60      else {
      61          status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv);
      62      }
      63      if (_PyStatus_EXCEPTION(status)) {
      64          goto done;
      65      }
      66  
      67      status = Py_InitializeFromConfig(&config);
      68      if (_PyStatus_EXCEPTION(status)) {
      69          goto done;
      70      }
      71      status = _PyStatus_OK();
      72  
      73  done:
      74      PyConfig_Clear(&config);
      75      return status;
      76  }
      77  
      78  
      79  /* --- pymain_run_python() ---------------------------------------- */
      80  
      81  /* Non-zero if filename, command (-c) or module (-m) is set
      82     on the command line */
      83  static inline int config_run_code(const PyConfig *config)
      84  {
      85      return (config->run_command != NULL
      86              || config->run_filename != NULL
      87              || config->run_module != NULL);
      88  }
      89  
      90  
      91  /* Return non-zero if stdin is a TTY or if -i command line option is used */
      92  static int
      93  stdin_is_interactive(const PyConfig *config)
      94  {
      95      return (isatty(fileno(stdin)) || config->interactive);
      96  }
      97  
      98  
      99  /* Display the current Python exception and return an exitcode */
     100  static int
     101  pymain_err_print(int *exitcode_p)
     102  {
     103      int exitcode;
     104      if (_Py_HandleSystemExit(&exitcode)) {
     105          *exitcode_p = exitcode;
     106          return 1;
     107      }
     108  
     109      PyErr_Print();
     110      return 0;
     111  }
     112  
     113  
     114  static int
     115  pymain_exit_err_print(void)
     116  {
     117      int exitcode = 1;
     118      pymain_err_print(&exitcode);
     119      return exitcode;
     120  }
     121  
     122  
     123  /* Write an exitcode into *exitcode and return 1 if we have to exit Python.
     124     Return 0 otherwise. */
     125  static int
     126  pymain_get_importer(const wchar_t *filename, PyObject **importer_p, int *exitcode)
     127  {
     128      PyObject *sys_path0 = NULL, *importer;
     129  
     130      sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
     131      if (sys_path0 == NULL) {
     132          goto error;
     133      }
     134  
     135      importer = PyImport_GetImporter(sys_path0);
     136      if (importer == NULL) {
     137          goto error;
     138      }
     139  
     140      if (importer == Py_None) {
     141          Py_DECREF(sys_path0);
     142          Py_DECREF(importer);
     143          return 0;
     144      }
     145  
     146      Py_DECREF(importer);
     147      *importer_p = sys_path0;
     148      return 0;
     149  
     150  error:
     151      Py_XDECREF(sys_path0);
     152  
     153      PySys_WriteStderr("Failed checking if argv[0] is an import path entry\n");
     154      return pymain_err_print(exitcode);
     155  }
     156  
     157  
     158  static int
     159  pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
     160  {
     161      PyObject *sys_path;
     162      PyObject *sysdict = interp->sysdict;
     163      if (sysdict != NULL) {
     164          sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path));
     165          if (sys_path == NULL && PyErr_Occurred()) {
     166              return -1;
     167          }
     168      }
     169      else {
     170          sys_path = NULL;
     171      }
     172      if (sys_path == NULL) {
     173          PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
     174          return -1;
     175      }
     176  
     177      if (PyList_Insert(sys_path, 0, path0)) {
     178          return -1;
     179      }
     180      return 0;
     181  }
     182  
     183  
     184  static void
     185  pymain_header(const PyConfig *config)
     186  {
     187      if (config->quiet) {
     188          return;
     189      }
     190  
     191      if (!config->verbose && (config_run_code(config) || !stdin_is_interactive(config))) {
     192          return;
     193      }
     194  
     195      fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
     196      if (config->site_import) {
     197          fprintf(stderr, "%s\n", COPYRIGHT);
     198      }
     199  }
     200  
     201  
     202  static void
     203  pymain_import_readline(const PyConfig *config)
     204  {
     205      if (config->isolated) {
     206          return;
     207      }
     208      if (!config->inspect && config_run_code(config)) {
     209          return;
     210      }
     211      if (!isatty(fileno(stdin))) {
     212          return;
     213      }
     214  
     215      PyObject *mod = PyImport_ImportModule("readline");
     216      if (mod == NULL) {
     217          PyErr_Clear();
     218      }
     219      else {
     220          Py_DECREF(mod);
     221      }
     222      mod = PyImport_ImportModule("rlcompleter");
     223      if (mod == NULL) {
     224          PyErr_Clear();
     225      }
     226      else {
     227          Py_DECREF(mod);
     228      }
     229  }
     230  
     231  
     232  static int
     233  pymain_run_command(wchar_t *command)
     234  {
     235      PyObject *unicode, *bytes;
     236      int ret;
     237  
     238      unicode = PyUnicode_FromWideChar(command, -1);
     239      if (unicode == NULL) {
     240          goto error;
     241      }
     242  
     243      if (PySys_Audit("cpython.run_command", "O", unicode) < 0) {
     244          return pymain_exit_err_print();
     245      }
     246  
     247      bytes = PyUnicode_AsUTF8String(unicode);
     248      Py_DECREF(unicode);
     249      if (bytes == NULL) {
     250          goto error;
     251      }
     252  
     253      PyCompilerFlags cf = _PyCompilerFlags_INIT;
     254      cf.cf_flags |= PyCF_IGNORE_COOKIE;
     255      ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), &cf);
     256      Py_DECREF(bytes);
     257      return (ret != 0);
     258  
     259  error:
     260      PySys_WriteStderr("Unable to decode the command from the command line:\n");
     261      return pymain_exit_err_print();
     262  }
     263  
     264  
     265  static int
     266  pymain_run_module(const wchar_t *modname, int set_argv0)
     267  {
     268      PyObject *module, *runpy, *runmodule, *runargs, *result;
     269      if (PySys_Audit("cpython.run_module", "u", modname) < 0) {
     270          return pymain_exit_err_print();
     271      }
     272      runpy = PyImport_ImportModule("runpy");
     273      if (runpy == NULL) {
     274          fprintf(stderr, "Could not import runpy module\n");
     275          return pymain_exit_err_print();
     276      }
     277      runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
     278      if (runmodule == NULL) {
     279          fprintf(stderr, "Could not access runpy._run_module_as_main\n");
     280          Py_DECREF(runpy);
     281          return pymain_exit_err_print();
     282      }
     283      module = PyUnicode_FromWideChar(modname, wcslen(modname));
     284      if (module == NULL) {
     285          fprintf(stderr, "Could not convert module name to unicode\n");
     286          Py_DECREF(runpy);
     287          Py_DECREF(runmodule);
     288          return pymain_exit_err_print();
     289      }
     290      runargs = PyTuple_Pack(2, module, set_argv0 ? Py_True : Py_False);
     291      if (runargs == NULL) {
     292          fprintf(stderr,
     293              "Could not create arguments for runpy._run_module_as_main\n");
     294          Py_DECREF(runpy);
     295          Py_DECREF(runmodule);
     296          Py_DECREF(module);
     297          return pymain_exit_err_print();
     298      }
     299      _PyRuntime.signals.unhandled_keyboard_interrupt = 0;
     300      result = PyObject_Call(runmodule, runargs, NULL);
     301      if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) {
     302          _PyRuntime.signals.unhandled_keyboard_interrupt = 1;
     303      }
     304      Py_DECREF(runpy);
     305      Py_DECREF(runmodule);
     306      Py_DECREF(module);
     307      Py_DECREF(runargs);
     308      if (result == NULL) {
     309          return pymain_exit_err_print();
     310      }
     311      Py_DECREF(result);
     312      return 0;
     313  }
     314  
     315  
     316  static int
     317  pymain_run_file_obj(PyObject *program_name, PyObject *filename,
     318                      int skip_source_first_line)
     319  {
     320      if (PySys_Audit("cpython.run_file", "O", filename) < 0) {
     321          return pymain_exit_err_print();
     322      }
     323  
     324      FILE *fp = _Py_fopen_obj(filename, "rb");
     325      if (fp == NULL) {
     326          // Ignore the OSError
     327          PyErr_Clear();
     328          PySys_FormatStderr("%S: can't open file %R: [Errno %d] %s\n",
     329                             program_name, filename, errno, strerror(errno));
     330          return 2;
     331      }
     332  
     333      if (skip_source_first_line) {
     334          int ch;
     335          /* Push back first newline so line numbers remain the same */
     336          while ((ch = getc(fp)) != EOF) {
     337              if (ch == '\n') {
     338                  (void)ungetc(ch, fp);
     339                  break;
     340              }
     341          }
     342      }
     343  
     344      struct _Py_stat_struct sb;
     345      if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) {
     346          PySys_FormatStderr("%S: %R is a directory, cannot continue\n",
     347                             program_name, filename);
     348          fclose(fp);
     349          return 1;
     350      }
     351  
     352      // Call pending calls like signal handlers (SIGINT)
     353      if (Py_MakePendingCalls() == -1) {
     354          fclose(fp);
     355          return pymain_exit_err_print();
     356      }
     357  
     358      /* PyRun_AnyFileExFlags(closeit=1) calls fclose(fp) before running code */
     359      PyCompilerFlags cf = _PyCompilerFlags_INIT;
     360      int run = _PyRun_AnyFileObject(fp, filename, 1, &cf);
     361      return (run != 0);
     362  }
     363  
     364  static int
     365  pymain_run_file(const PyConfig *config)
     366  {
     367      PyObject *filename = PyUnicode_FromWideChar(config->run_filename, -1);
     368      if (filename == NULL) {
     369          PyErr_Print();
     370          return -1;
     371      }
     372      PyObject *program_name = PyUnicode_FromWideChar(config->program_name, -1);
     373      if (program_name == NULL) {
     374          Py_DECREF(filename);
     375          PyErr_Print();
     376          return -1;
     377      }
     378  
     379      int res = pymain_run_file_obj(program_name, filename,
     380                                    config->skip_source_first_line);
     381      Py_DECREF(filename);
     382      Py_DECREF(program_name);
     383      return res;
     384  }
     385  
     386  
     387  static int
     388  pymain_run_startup(PyConfig *config, int *exitcode)
     389  {
     390      int ret;
     391      if (!config->use_environment) {
     392          return 0;
     393      }
     394      PyObject *startup = NULL;
     395  #ifdef MS_WINDOWS
     396      const wchar_t *env = _wgetenv(L"PYTHONSTARTUP");
     397      if (env == NULL || env[0] == L'\0') {
     398          return 0;
     399      }
     400      startup = PyUnicode_FromWideChar(env, wcslen(env));
     401      if (startup == NULL) {
     402          goto error;
     403      }
     404  #else
     405      const char *env = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP");
     406      if (env == NULL) {
     407          return 0;
     408      }
     409      startup = PyUnicode_DecodeFSDefault(env);
     410      if (startup == NULL) {
     411          goto error;
     412      }
     413  #endif
     414      if (PySys_Audit("cpython.run_startup", "O", startup) < 0) {
     415          goto error;
     416      }
     417  
     418      FILE *fp = _Py_fopen_obj(startup, "r");
     419      if (fp == NULL) {
     420          int save_errno = errno;
     421          PyErr_Clear();
     422          PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
     423  
     424          errno = save_errno;
     425          PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, startup, NULL);
     426          goto error;
     427      }
     428  
     429      PyCompilerFlags cf = _PyCompilerFlags_INIT;
     430      (void) _PyRun_SimpleFileObject(fp, startup, 0, &cf);
     431      PyErr_Clear();
     432      fclose(fp);
     433      ret = 0;
     434  
     435  done:
     436      Py_XDECREF(startup);
     437      return ret;
     438  
     439  error:
     440      ret = pymain_err_print(exitcode);
     441      goto done;
     442  }
     443  
     444  
     445  /* Write an exitcode into *exitcode and return 1 if we have to exit Python.
     446     Return 0 otherwise. */
     447  static int
     448  pymain_run_interactive_hook(int *exitcode)
     449  {
     450      PyObject *sys, *hook, *result;
     451      sys = PyImport_ImportModule("sys");
     452      if (sys == NULL) {
     453          goto error;
     454      }
     455  
     456      hook = PyObject_GetAttrString(sys, "__interactivehook__");
     457      Py_DECREF(sys);
     458      if (hook == NULL) {
     459          PyErr_Clear();
     460          return 0;
     461      }
     462  
     463      if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
     464          goto error;
     465      }
     466  
     467      result = _PyObject_CallNoArgs(hook);
     468      Py_DECREF(hook);
     469      if (result == NULL) {
     470          goto error;
     471      }
     472      Py_DECREF(result);
     473  
     474      return 0;
     475  
     476  error:
     477      PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
     478      return pymain_err_print(exitcode);
     479  }
     480  
     481  
     482  static void
     483  pymain_set_inspect(PyConfig *config, int inspect)
     484  {
     485      config->inspect = inspect;
     486  _Py_COMP_DIAG_PUSH
     487  _Py_COMP_DIAG_IGNORE_DEPR_DECLS
     488      Py_InspectFlag = inspect;
     489  _Py_COMP_DIAG_POP
     490  }
     491  
     492  
     493  static int
     494  pymain_run_stdin(PyConfig *config)
     495  {
     496      if (stdin_is_interactive(config)) {
     497          // do exit on SystemExit
     498          pymain_set_inspect(config, 0);
     499  
     500          int exitcode;
     501          if (pymain_run_startup(config, &exitcode)) {
     502              return exitcode;
     503          }
     504  
     505          if (pymain_run_interactive_hook(&exitcode)) {
     506              return exitcode;
     507          }
     508      }
     509  
     510      /* call pending calls like signal handlers (SIGINT) */
     511      if (Py_MakePendingCalls() == -1) {
     512          return pymain_exit_err_print();
     513      }
     514  
     515      if (PySys_Audit("cpython.run_stdin", NULL) < 0) {
     516          return pymain_exit_err_print();
     517      }
     518  
     519      PyCompilerFlags cf = _PyCompilerFlags_INIT;
     520      int run = PyRun_AnyFileExFlags(stdin, "<stdin>", 0, &cf);
     521      return (run != 0);
     522  }
     523  
     524  
     525  static void
     526  pymain_repl(PyConfig *config, int *exitcode)
     527  {
     528      /* Check this environment variable at the end, to give programs the
     529         opportunity to set it from Python. */
     530      if (!config->inspect && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
     531          pymain_set_inspect(config, 1);
     532      }
     533  
     534      if (!(config->inspect && stdin_is_interactive(config) && config_run_code(config))) {
     535          return;
     536      }
     537  
     538      pymain_set_inspect(config, 0);
     539      if (pymain_run_interactive_hook(exitcode)) {
     540          return;
     541      }
     542  
     543      PyCompilerFlags cf = _PyCompilerFlags_INIT;
     544      int res = PyRun_AnyFileFlags(stdin, "<stdin>", &cf);
     545      *exitcode = (res != 0);
     546  }
     547  
     548  
     549  static void
     550  pymain_run_python(int *exitcode)
     551  {
     552      PyObject *main_importer_path = NULL;
     553      PyInterpreterState *interp = _PyInterpreterState_GET();
     554      /* pymain_run_stdin() modify the config */
     555      PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp);
     556  
     557      /* ensure path config is written into global variables */
     558      if (_PyStatus_EXCEPTION(_PyPathConfig_UpdateGlobal(config))) {
     559          goto error;
     560      }
     561  
     562      if (config->run_filename != NULL) {
     563          /* If filename is a package (ex: directory or ZIP file) which contains
     564             __main__.py, main_importer_path is set to filename and will be
     565             prepended to sys.path.
     566  
     567             Otherwise, main_importer_path is left unchanged. */
     568          if (pymain_get_importer(config->run_filename, &main_importer_path,
     569                                  exitcode)) {
     570              return;
     571          }
     572      }
     573  
     574      // import readline and rlcompleter before script dir is added to sys.path
     575      pymain_import_readline(config);
     576  
     577      if (main_importer_path != NULL) {
     578          if (pymain_sys_path_add_path0(interp, main_importer_path) < 0) {
     579              goto error;
     580          }
     581      }
     582      else if (!config->safe_path) {
     583          PyObject *path0 = NULL;
     584          int res = _PyPathConfig_ComputeSysPath0(&config->argv, &path0);
     585          if (res < 0) {
     586              goto error;
     587          }
     588  
     589          if (res > 0) {
     590              if (pymain_sys_path_add_path0(interp, path0) < 0) {
     591                  Py_DECREF(path0);
     592                  goto error;
     593              }
     594              Py_DECREF(path0);
     595          }
     596      }
     597  
     598      pymain_header(config);
     599  
     600      if (config->run_command) {
     601          *exitcode = pymain_run_command(config->run_command);
     602      }
     603      else if (config->run_module) {
     604          *exitcode = pymain_run_module(config->run_module, 1);
     605      }
     606      else if (main_importer_path != NULL) {
     607          *exitcode = pymain_run_module(L"__main__", 0);
     608      }
     609      else if (config->run_filename != NULL) {
     610          *exitcode = pymain_run_file(config);
     611      }
     612      else {
     613          *exitcode = pymain_run_stdin(config);
     614      }
     615  
     616      pymain_repl(config, exitcode);
     617      goto done;
     618  
     619  error:
     620      *exitcode = pymain_exit_err_print();
     621  
     622  done:
     623      Py_XDECREF(main_importer_path);
     624  }
     625  
     626  
     627  /* --- pymain_main() ---------------------------------------------- */
     628  
     629  static void
     630  pymain_free(void)
     631  {
     632      _PyImport_Fini2();
     633  
     634      /* Free global variables which cannot be freed in Py_Finalize():
     635         configuration options set before Py_Initialize() which should
     636         remain valid after Py_Finalize(), since
     637         Py_Initialize()-Py_Finalize() can be called multiple times. */
     638      _PyPathConfig_ClearGlobal();
     639      _Py_ClearStandardStreamEncoding();
     640      _Py_ClearArgcArgv();
     641      _PyRuntime_Finalize();
     642  }
     643  
     644  
     645  static int
     646  exit_sigint(void)
     647  {
     648      /* bpo-1054041: We need to exit via the
     649       * SIG_DFL handler for SIGINT if KeyboardInterrupt went unhandled.
     650       * If we don't, a calling process such as a shell may not know
     651       * about the user's ^C.  https://www.cons.org/cracauer/sigint.html */
     652  #if defined(HAVE_GETPID) && defined(HAVE_KILL) && !defined(MS_WINDOWS)
     653      if (PyOS_setsig(SIGINT, SIG_DFL) == SIG_ERR) {
     654          perror("signal");  /* Impossible in normal environments. */
     655      } else {
     656          kill(getpid(), SIGINT);
     657      }
     658      /* If setting SIG_DFL failed, or kill failed to terminate us,
     659       * there isn't much else we can do aside from an error code. */
     660  #endif  /* HAVE_GETPID && !MS_WINDOWS */
     661  #ifdef MS_WINDOWS
     662      /* cmd.exe detects this, prints ^C, and offers to terminate. */
     663      /* https://msdn.microsoft.com/en-us/library/cc704588.aspx */
     664      return STATUS_CONTROL_C_EXIT;
     665  #else
     666      return SIGINT + 128;
     667  #endif  /* !MS_WINDOWS */
     668  }
     669  
     670  
     671  static void _Py_NO_RETURN
     672  pymain_exit_error(PyStatus status)
     673  {
     674      if (_PyStatus_IS_EXIT(status)) {
     675          /* If it's an error rather than a regular exit, leave Python runtime
     676             alive: Py_ExitStatusException() uses the current exception and use
     677             sys.stdout in this case. */
     678          pymain_free();
     679      }
     680      Py_ExitStatusException(status);
     681  }
     682  
     683  
     684  int
     685  Py_RunMain(void)
     686  {
     687      int exitcode = 0;
     688  
     689      pymain_run_python(&exitcode);
     690  
     691      if (Py_FinalizeEx() < 0) {
     692          /* Value unlikely to be confused with a non-error exit status or
     693             other special meaning */
     694          exitcode = 120;
     695      }
     696  
     697      pymain_free();
     698  
     699      if (_PyRuntime.signals.unhandled_keyboard_interrupt) {
     700          exitcode = exit_sigint();
     701      }
     702  
     703      return exitcode;
     704  }
     705  
     706  
     707  static int
     708  pymain_main(_PyArgv *args)
     709  {
     710      PyStatus status = pymain_init(args);
     711      if (_PyStatus_IS_EXIT(status)) {
     712          pymain_free();
     713          return status.exitcode;
     714      }
     715      if (_PyStatus_EXCEPTION(status)) {
     716          pymain_exit_error(status);
     717      }
     718  
     719      return Py_RunMain();
     720  }
     721  
     722  
     723  int
     724  Py_Main(int argc, wchar_t **argv)
     725  {
     726      _PyArgv args = {
     727          .argc = argc,
     728          .use_bytes_argv = 0,
     729          .bytes_argv = NULL,
     730          .wchar_argv = argv};
     731      return pymain_main(&args);
     732  }
     733  
     734  
     735  int
     736  Py_BytesMain(int argc, char **argv)
     737  {
     738      _PyArgv args = {
     739          .argc = argc,
     740          .use_bytes_argv = 1,
     741          .bytes_argv = argv,
     742          .wchar_argv = NULL};
     743      return pymain_main(&args);
     744  }
     745  
     746  #ifdef __cplusplus
     747  }
     748  #endif