sendpraat.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /* sendpraat.c */
  2. /* by Paul Boersma */
  3. /* 21 August 2017 */
  4. /*
  5. * The sendpraat subroutine (Unix with GTK; Windows; Macintosh) sends a message
  6. * to a running Praat (or another program that uses the Praat shell).
  7. * The sendpraat program behaves identically from a Unix command shell,
  8. * from a Windows console, or from a MacOS X terminal window.
  9. *
  10. * Newer versions of sendpraat may be found at http://www.praat.org or http://www.fon.hum.uva.nl/praat/sendpraat.html
  11. *
  12. * On Windows, this version works only with Praat version 4.3.28 (November 2005) or newer.
  13. * On Macintosh, this version works only with Praat version 3.8.75 (October 2000) or newer.
  14. * On Unix with GTK, this version works only with Praat version 5.1.33 (May 2010) or newer.
  15. * Newer versions of Praat may respond faster or more reliably.
  16. */
  17. /*******************************************************************
  18. THIS CODE CAN BE COPIED, USED, AND DISTRIBUTED FREELY.
  19. IF YOU MODIFY IT, PLEASE KEEP MY NAME AND MARK THE CHANGES.
  20. IF YOU IMPROVE IT, PLEASE NOTIFY ME AT paul.boersma@uva.nl.
  21. *******************************************************************/
  22. #if defined (_WIN32)
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <wchar.h>
  26. #ifdef __MINGW32__
  27. #define swprintf _snwprintf
  28. #endif
  29. #define gtk 0
  30. #define win 1
  31. #define mac 0
  32. #elif (defined (macintosh) || defined (__MACH__))
  33. #include <Carbon/Carbon.h>
  34. #include <wchar.h>
  35. #define gtk 0
  36. #define win 0
  37. #define mac 1
  38. #elif defined (UNIX)
  39. #include <sys/types.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include <ctype.h>
  46. #include <wchar.h>
  47. #if defined (NO_GRAPHICS) || defined (NO_GUI) /* for use inside Praat */
  48. #define gtk 0
  49. #else
  50. #include <gtk/gtk.h>
  51. #define gtk 1
  52. #endif
  53. #define win 0
  54. #define mac 0
  55. #else
  56. #include <wchar.h>
  57. #define gtk 0
  58. #define win 0
  59. #define mac 0
  60. #endif
  61. /*
  62. * The way to call the sendpraat subroutine from another program.
  63. */
  64. char *sendpraat (void *display, const char *programName, long timeOut, const char *text);
  65. wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, const wchar_t *text);
  66. /*
  67. * Parameters:
  68. * 'display' is the Display or GdkDisplay pointer, which will be available if you call sendpraat from an X11 or GTK program.
  69. * If 'display' is NULL, sendpraat will open the display by itself, and close it after use.
  70. * On Windows and Macintosh, sendpraat ignores the 'display' parameter.
  71. * 'programName' is the name of the program that receives the message.
  72. * This program must have been built with the Praat shell (the most common such programs are Praat and ALS).
  73. * On Unix, the program name is usually all lower case, e.g. "praat" or "als", or the name of any other program.
  74. * On Windows, you can use either "Praat", "praat", or the name of any other program.
  75. * On Macintosh, 'programName' must be "Praat", "praat", "ALS", or the Macintosh signature of any other program.
  76. * 'timeOut' is the time (in seconds) after which sendpraat will return with a time-out error message
  77. * if the receiving program sends no notification of completion.
  78. * On Unix and Macintosh, the message is sent asynchronously if 'timeOut' is 0;
  79. * this means that sendpraat will return OK (NULL) without waiting for the receiving program
  80. * to handle the message.
  81. * On Windows, the time out is ignored.
  82. * 'text' contains the contents of the Praat script to be sent to the receiving program.
  83. */
  84. static char errorMessage [1000];
  85. static wchar_t errorMessageW [1000];
  86. #if gtk
  87. static long theTimeOut;
  88. static void handleCompletion (int message) { (void) message; }
  89. static void handleTimeOut (int message) { (void) message; sprintf (errorMessage, "Timed out after %ld seconds.", theTimeOut); }
  90. #endif
  91. char *sendpraat (void *display, const char *programName, long timeOut, const char *text) {
  92. char nativeProgramName [100];
  93. #if gtk
  94. char *home, pidFileName [256], messageFileName [256];
  95. FILE *pidFile;
  96. long pid, wid = 0;
  97. #elif win
  98. char homeDirectory [256], messageFileName [256], windowName [256];
  99. HWND window;
  100. (void) display;
  101. (void) timeOut;
  102. #elif mac
  103. AEDesc programDescriptor;
  104. AppleEvent event, reply;
  105. OSStatus err;
  106. UInt32 signature;
  107. (void) display;
  108. #endif
  109. /*
  110. * Clean up from an earlier call.
  111. */
  112. errorMessage [0] = '\0';
  113. /*
  114. * Handle case differences.
  115. */
  116. strcpy (nativeProgramName, programName);
  117. #if gtk
  118. nativeProgramName [0] = tolower (nativeProgramName [0]);
  119. #else
  120. nativeProgramName [0] = toupper (nativeProgramName [0]);
  121. #endif
  122. /*
  123. * If the text is going to be sent in a file, create its name.
  124. * The file is going to be written into the preferences directory of the receiving program.
  125. * On Unix, the name will be something like /home/jane/.praat-dir/message.
  126. * On Windows, the name will be something like C:\Users\Jane\Praat\Message.txt,
  127. * or C:\Windows\Praat\Message.txt on older systems.
  128. * On Macintosh, the text is NOT going to be sent in a file.
  129. */
  130. #if gtk
  131. if ((home = getenv ("HOME")) == NULL) {
  132. sprintf (errorMessage, "HOME environment variable not set.");
  133. return errorMessage;
  134. }
  135. sprintf (messageFileName, "%s/.%s-dir/message", home, programName);
  136. #elif win
  137. if (GetEnvironmentVariableA ("USERPROFILE", homeDirectory, 255)) {
  138. ; /* Ready. */
  139. } else if (GetEnvironmentVariableA ("HOMEDRIVE", homeDirectory, 255)) {
  140. GetEnvironmentVariableA ("HOMEPATH", homeDirectory + strlen (homeDirectory), 255);
  141. } else {
  142. GetWindowsDirectoryA (homeDirectory, 255);
  143. }
  144. sprintf (messageFileName, "%s\\%s\\Message.txt", homeDirectory, programName);
  145. #endif
  146. /*
  147. * Save the message file (Unix and Windows only).
  148. */
  149. #if gtk || win
  150. {
  151. FILE *messageFile;
  152. if ((messageFile = fopen (messageFileName, "w")) == NULL) {
  153. sprintf (errorMessage, "Cannot create message file \"%s\" "
  154. "(no privilege to write to directory, or disk full, or program is not called %s).\n", messageFileName, programName);
  155. return errorMessage;
  156. }
  157. #if gtk
  158. if (timeOut)
  159. fprintf (messageFile, "#%ld\n", (long) getpid ()); /* Write own process ID for callback. */
  160. #endif
  161. fprintf (messageFile, "%s", text);
  162. fclose (messageFile);
  163. }
  164. #endif
  165. /*
  166. * Where shall we send the message?
  167. */
  168. #if gtk
  169. /*
  170. * Get the process ID and the window ID of a running Praat-shell program.
  171. */
  172. sprintf (pidFileName, "%s/.%s-dir/pid", home, programName);
  173. if ((pidFile = fopen (pidFileName, "r")) == NULL) {
  174. sprintf (errorMessage, "Program %s not running.", programName);
  175. return errorMessage;
  176. }
  177. if (fscanf (pidFile, "%ld%ld", & pid, & wid) < 1) {
  178. fclose (pidFile);
  179. sprintf (errorMessage, "Program %s not running, or disk has been full.", programName);
  180. return errorMessage;
  181. }
  182. fclose (pidFile);
  183. #elif win
  184. /*
  185. * Get the window handle of the "Objects" window of a running Praat-shell program.
  186. */
  187. sprintf (windowName, "PraatShell1 %s", programName);
  188. window = FindWindowA (windowName, NULL);
  189. if (! window) {
  190. sprintf (errorMessage, "Program %s not running (or an old version).", programName);
  191. return errorMessage;
  192. }
  193. #elif mac
  194. /*
  195. * Convert the program name to a Macintosh signature.
  196. * I know of no system routine for this, so I'll just translate the two most common names:
  197. */
  198. if (! strcmp (programName, "praat") || ! strcmp (programName, "Praat") || ! strcmp (programName, "PRAAT"))
  199. signature = 'PpgB';
  200. else if (! strcmp (programName, "als") || ! strcmp (programName, "Als") || ! strcmp (programName, "ALS"))
  201. signature = 'CclA';
  202. else
  203. signature = 0;
  204. AECreateDesc (typeApplSignature, & signature, 4, & programDescriptor);
  205. #endif
  206. /*
  207. * Send the message.
  208. */
  209. #if gtk
  210. /*
  211. * Be ready to receive notification of completion.
  212. */
  213. if (timeOut)
  214. signal (SIGUSR2, handleCompletion);
  215. /*
  216. * Notify running program.
  217. */
  218. if (wid != 0) { /* Praat shell version October 21, 1998 or later? Send event to window. */
  219. /*
  220. * Notify main window.
  221. */
  222. GdkEventClient gevent;
  223. #if !GLIB_CHECK_VERSION(2,35,0)
  224. g_type_init ();
  225. #endif
  226. int displaySupplied = display != NULL;
  227. if (! displaySupplied) {
  228. display = gdk_display_open (getenv ("DISPLAY")); /* GdkDisplay* */
  229. if (display == NULL) {
  230. sprintf (errorMessage, "Cannot open display %s", getenv ("DISPLAY"));
  231. return errorMessage;
  232. }
  233. }
  234. gevent. type = GDK_CLIENT_EVENT;
  235. gevent. window = 0;
  236. gevent. send_event = 1;
  237. gevent. message_type = gdk_atom_intern_static_string ("SENDPRAAT");
  238. gevent. data_format = 8;
  239. if (! gdk_event_send_client_message_for_display (display, (GdkEvent *) & gevent, wid)) {
  240. if (! displaySupplied) gdk_display_close (display);
  241. sprintf (errorMessage, "Cannot send message to %s (window %ld). "
  242. "The program %s may have been started by a different user, "
  243. "or may have crashed.", programName, wid, programName);
  244. return errorMessage;
  245. }
  246. if (! displaySupplied) gdk_display_close (display);
  247. }
  248. /*
  249. * Wait for the running program to notify us of completion,
  250. * but do not wait for more than 'timeOut' seconds.
  251. */
  252. if (timeOut) {
  253. signal (SIGALRM, handleTimeOut);
  254. alarm (timeOut);
  255. theTimeOut = timeOut; // hand an argument to handleTimeOut () in a static variable
  256. errorMessage [0] = '\0';
  257. pause ();
  258. if (errorMessage [0] != '\0') return errorMessage;
  259. }
  260. #elif win
  261. /*
  262. * Notify the running program by sending a WM_USER message to its main window.
  263. */
  264. if (SendMessage (window, WM_USER, 0, 0)) {
  265. sprintf (errorMessage, "Program %s returns error.", programName); // BUG?
  266. return errorMessage;
  267. }
  268. #elif mac
  269. /*
  270. * Notify the running program by sending it an Apple event of the magic class 758934755.
  271. */
  272. AECreateAppleEvent (758934755, 0, & programDescriptor, kAutoGenerateReturnID, 1, & event);
  273. AEPutParamPtr (& event, 1, typeChar, text, strlen (text) + 1);
  274. #ifdef __MACH__
  275. err = AESendMessage (& event, & reply,
  276. ( timeOut == 0 ? kAENoReply : kAEWaitReply ) | kAECanInteract | kAECanSwitchLayer,
  277. timeOut == 0 ? kNoTimeOut : 60 * timeOut);
  278. #else
  279. err = AESend (& event, & reply,
  280. ( timeOut == 0 ? kAENoReply : kAEWaitReply ) | kAECanInteract | kAECanSwitchLayer,
  281. kAENormalPriority, timeOut == 0 ? kNoTimeOut : 60 * timeOut, NULL, NULL);
  282. #endif
  283. if (err != noErr) {
  284. if (err == procNotFound || err == connectionInvalid)
  285. sprintf (errorMessage, "Could not send message to program \"%s\".\n"
  286. "The program is probably not running (or an old version).", programName);
  287. else if (err == errAETimeout)
  288. sprintf (errorMessage, "Message to program \"%s\" timed out "
  289. "after %ld seconds, before completion.", programName, timeOut);
  290. else
  291. sprintf (errorMessage, "Unexpected sendpraat error %d.\nNotify the author.", err);
  292. }
  293. AEDisposeDesc (& programDescriptor);
  294. AEDisposeDesc (& event);
  295. AEDisposeDesc (& reply);
  296. #endif
  297. /*
  298. * Notify the caller of success (NULL pointer) or failure (string with an error message).
  299. */
  300. return errorMessage [0] == '\0' ? NULL : errorMessage;
  301. }
  302. #ifndef __CYGWIN__
  303. wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, const wchar_t *text) {
  304. wchar_t nativeProgramName [100];
  305. #if gtk
  306. char *home, pidFileName [256], messageFileName [256];
  307. FILE *pidFile;
  308. long pid, wid = 0;
  309. #elif win
  310. wchar_t homeDirectory [256], messageFileName [256], windowName [256];
  311. HWND window;
  312. (void) display;
  313. (void) timeOut;
  314. #elif mac
  315. AEDesc programDescriptor;
  316. AppleEvent event, reply;
  317. OSStatus err;
  318. UInt32 signature;
  319. (void) display;
  320. #endif
  321. /*
  322. * Clean up from an earlier call.
  323. */
  324. errorMessageW [0] = '\0';
  325. /*
  326. * Handle case differences.
  327. */
  328. wcscpy (nativeProgramName, programName);
  329. #if gtk
  330. nativeProgramName [0] = tolower (nativeProgramName [0]);
  331. #else
  332. nativeProgramName [0] = toupper (nativeProgramName [0]);
  333. #endif
  334. /*
  335. * If the text is going to be sent in a file, create its name.
  336. * The file is going to be written into the preferences directory of the receiving program.
  337. * On Unix, the name will be something like /home/jane/.praat-dir/message.
  338. * On Windows, the name will be something like C:\Users\Jane\Praat\Message.txt,
  339. * or C:\Windows\Praat\Message.txt on older systems.
  340. * On Macintosh, the text is NOT going to be sent in a file.
  341. */
  342. #if gtk
  343. if ((home = getenv ("HOME")) == NULL) {
  344. swprintf (errorMessageW, 1000, L"HOME environment variable not set.");
  345. return errorMessageW;
  346. }
  347. sprintf (messageFileName, "%s/.%ls-dir/message", home, programName);
  348. #elif win
  349. if (GetEnvironmentVariableW (L"USERPROFILE", homeDirectory, 255)) {
  350. ; /* Ready. */
  351. } else if (GetEnvironmentVariableW (L"HOMEDRIVE", homeDirectory, 255)) {
  352. GetEnvironmentVariableW (L"HOMEPATH", homeDirectory + wcslen (homeDirectory), 255);
  353. } else {
  354. GetWindowsDirectoryW (homeDirectory, 255);
  355. }
  356. swprintf (messageFileName, 256, L"%ls\\%ls\\Message.txt", homeDirectory, programName);
  357. #endif
  358. /*
  359. * Save the message file (Unix and Windows only).
  360. */
  361. #if gtk
  362. FILE *messageFile;
  363. if ((messageFile = fopen (messageFileName, "w")) == NULL) {
  364. swprintf (errorMessageW, 1000, L"Cannot create message file \"%s\" "
  365. L"(no privilege to write to directory, or disk full).\n", messageFileName);
  366. return errorMessageW;
  367. }
  368. if (timeOut)
  369. fwprintf (messageFile, L"#%ld\n", (long) getpid ()); /* Write own process ID for callback. */
  370. fwprintf (messageFile, L"\ufeff%ls", text);
  371. fclose (messageFile);
  372. #elif win
  373. FILE *messageFile;
  374. if ((messageFile = _wfopen (messageFileName, L"w")) == NULL) {
  375. swprintf (errorMessageW, 1000, L"Cannot create message file \"%ls\" "
  376. L"(no privilege to write to directory, or disk full).\n", messageFileName);
  377. return errorMessageW;
  378. }
  379. fwprintf (messageFile, L"\ufeff%ls", text);
  380. fclose (messageFile);
  381. #endif
  382. /*
  383. * Where shall we send the message?
  384. */
  385. #if gtk
  386. /*
  387. * Get the process ID and the window ID of a running Praat-shell program.
  388. */
  389. sprintf (pidFileName, "%s/.%ls-dir/pid", home, programName);
  390. if ((pidFile = fopen (pidFileName, "r")) == NULL) {
  391. swprintf (errorMessageW, 1000, L"Program %ls not running.", programName);
  392. return errorMessageW;
  393. }
  394. if (fscanf (pidFile, "%ld%ld", & pid, & wid) < 1) {
  395. fclose (pidFile);
  396. swprintf (errorMessageW, 1000, L"Program %ls not running, or disk has been full.", programName);
  397. return errorMessageW;
  398. }
  399. fclose (pidFile);
  400. #elif win
  401. /*
  402. * Get the window handle of the "Objects" window of a running Praat-shell program.
  403. */
  404. swprintf (windowName, 256, L"PraatShell1 %ls", programName);
  405. window = FindWindowW (windowName, NULL);
  406. if (! window) {
  407. swprintf (errorMessageW, 1000, L"Program %ls not running (or an old version).", programName);
  408. return errorMessageW;
  409. }
  410. #elif mac
  411. /*
  412. * Convert the program name to a Macintosh signature.
  413. * I know of no system routine for this, so I'll just translate the two most common names:
  414. */
  415. if (! wcscmp (programName, L"praat") || ! wcscmp (programName, L"Praat") || ! wcscmp (programName, L"PRAAT"))
  416. signature = 'PpgB';
  417. else if (! wcscmp (programName, L"als") || ! wcscmp (programName, L"Als") || ! wcscmp (programName, L"ALS"))
  418. signature = 'CclA';
  419. else
  420. signature = 0;
  421. AECreateDesc (typeApplSignature, & signature, 4, & programDescriptor);
  422. #endif
  423. /*
  424. * Send the message.
  425. */
  426. #if gtk
  427. /*
  428. * Be ready to receive notification of completion.
  429. */
  430. if (timeOut)
  431. signal (SIGUSR2, handleCompletion);
  432. /*
  433. * Notify running program.
  434. */
  435. if (wid != 0) { /* Praat shell version October 21, 1998 or later? Send event to window. */
  436. /*
  437. * Notify main window.
  438. */
  439. GdkEventClient gevent;
  440. int displaySupplied = display != NULL;
  441. #if !GLIB_CHECK_VERSION(2,35,0)
  442. g_type_init ();
  443. #endif
  444. if (! displaySupplied) {
  445. display = gdk_display_open (getenv ("DISPLAY")); /* GdkDisplay* */
  446. if (display == NULL) {
  447. swprintf (errorMessageW, 1000, L"Cannot open display %s", getenv ("DISPLAY"));
  448. return errorMessageW;
  449. }
  450. }
  451. gevent. type = GDK_CLIENT_EVENT;
  452. gevent. window = 0;
  453. gevent. send_event = 1;
  454. gevent. message_type = gdk_atom_intern_static_string ("SENDPRAAT");
  455. gevent. data_format = 8;
  456. if (! gdk_event_send_client_message_for_display (display, (GdkEvent *) & gevent, wid)) {
  457. if (! displaySupplied) gdk_display_close (display);
  458. swprintf (errorMessageW, 1000, L"Cannot send message to %ls (window %ld). "
  459. "The program %ls may have been started by a different user, "
  460. "or may have crashed.", programName, (long) wid, programName);
  461. return errorMessageW;
  462. }
  463. if (! displaySupplied) gdk_display_close (display);
  464. }
  465. /*
  466. * Wait for the running program to notify us of completion,
  467. * but do not wait for more than 'timeOut' seconds.
  468. */
  469. if (timeOut) {
  470. signal (SIGALRM, handleTimeOut);
  471. alarm (timeOut);
  472. theTimeOut = timeOut; /* Hand an argument to handleTimeOut () in a static variable. */
  473. errorMessageW [0] = '\0';
  474. pause ();
  475. if (errorMessageW [0] != '\0') return errorMessageW;
  476. }
  477. #elif win
  478. /*
  479. * Notify the running program by sending a WM_USER message to its main window.
  480. */
  481. if (SendMessage (window, WM_USER, 0, 0)) {
  482. swprintf (errorMessageW, 1000, L"Program %ls returns error.", programName); /* BUG? */
  483. return errorMessageW;
  484. }
  485. #elif mac
  486. /*
  487. * Notify the running program by sending it an Apple event of the magic class 758934756.
  488. */
  489. AECreateAppleEvent (758934756, 0, & programDescriptor, kAutoGenerateReturnID, 1, & event);
  490. AEPutParamPtr (& event, 1, typeUnicodeText, text, wcslen (text) + 1);
  491. #ifdef __MACH__
  492. err = AESendMessage (& event, & reply,
  493. ( timeOut == 0 ? kAENoReply : kAEWaitReply ) | kAECanInteract | kAECanSwitchLayer,
  494. timeOut == 0 ? kNoTimeOut : 60 * timeOut);
  495. #else
  496. err = AESend (& event, & reply,
  497. ( timeOut == 0 ? kAENoReply : kAEWaitReply ) | kAECanInteract | kAECanSwitchLayer,
  498. kAENormalPriority, timeOut == 0 ? kNoTimeOut : 60 * timeOut, NULL, NULL);
  499. #endif
  500. if (err != noErr) {
  501. if (err == procNotFound || err == connectionInvalid)
  502. swprintf (errorMessageW, 1000, L"Could not send message to program \"%ls\".\n"
  503. L"The program is probably not running (or an old version).", programName);
  504. else if (err == errAETimeout)
  505. swprintf (errorMessageW, 1000, L"Message to program \"%ls\" timed out "
  506. L"after %ld seconds, before completion.", programName, timeOut);
  507. else
  508. swprintf (errorMessageW, 1000, L"Unexpected sendpraat error %d.\nNotify the author.", err);
  509. }
  510. AEDisposeDesc (& programDescriptor);
  511. AEDisposeDesc (& event);
  512. AEDisposeDesc (& reply);
  513. #endif
  514. /*
  515. * Notify the caller of success (NULL pointer) or failure (string with an error message).
  516. */
  517. return errorMessageW [0] == '\0' ? NULL : errorMessageW;
  518. }
  519. #endif
  520. /*
  521. * To compile sendpraat as a stand-alone program, use the -DSTAND_ALONE option to the C compiler:
  522. */
  523. #ifdef STAND_ALONE
  524. /*
  525. * To compile on MacOS X:
  526. cc -o sendpraat -DSTAND_ALONE -framework CoreServices -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers sendpraat.c -Dmacintosh
  527. *
  528. * To compile on Linux:
  529. cc -std=gnu99 -o sendpraat -DSTAND_ALONE -DUNIX `pkg-config --cflags --libs gtk+-2.0` sendpraat.c
  530. */
  531. int main (int argc, char **argv) {
  532. int iarg, line, length = 0;
  533. long timeOut = 10; /* Default. */
  534. char programName [64], *message, *result;
  535. if (argc == 1) {
  536. printf ("Syntax:\n");
  537. #if win
  538. printf (" sendpraat <program> <message>\n");
  539. #else
  540. printf (" sendpraat [<timeOut>] <program> <message>\n");
  541. #endif
  542. printf ("\n");
  543. printf ("Arguments:\n");
  544. printf (" <program>: the name of a running program that uses the Praat shell.\n");
  545. printf (" <message>: a sequence of Praat shell lines (commands and directives).\n");
  546. #if ! win
  547. printf (" <timeOut>: the number of seconds that sendpraat will wait for an answer\n");
  548. printf (" before writing an error message. A <timeOut> of 0 means that\n");
  549. printf (" the message will be sent asynchronously, i.e., that sendpraat\n");
  550. printf (" will return immediately without issuing any error message.\n");
  551. #endif
  552. printf ("\n");
  553. printf ("Usage:\n");
  554. printf (" Each line is a separate argument.\n");
  555. printf (" Lines that contain spaces should be put inside double quotes.\n");
  556. printf ("\n");
  557. printf ("Examples:\n");
  558. printf ("\n");
  559. #if win
  560. printf (" sendpraat praat Quit\n");
  561. #else
  562. printf (" sendpraat 0 praat Quit\n");
  563. #endif
  564. printf (" Causes the program \"praat\" to quit (gracefully).\n");
  565. printf (" This works because \"Quit\" is a fixed command in Praat's Control menu.\n");
  566. #if ! win
  567. printf (" Sendpraat will return immediately.\n");
  568. #endif
  569. printf ("\n");
  570. #if win
  571. printf (" sendpraat praat \"Play reverse\"\n");
  572. #else
  573. printf (" sendpraat 1000 praat \"Play reverse\"\n");
  574. #endif
  575. printf (" Causes the program \"praat\", which can play sounds,\n");
  576. printf (" to play the selected Sound objects backwards.\n");
  577. printf (" This works because \"Play reverse\" is an action command\n");
  578. printf (" that becomes available in Praat's dynamic menu when Sounds are selected.\n");
  579. #if ! win
  580. printf (" Sendpraat will allow \"praat\" at most 1000 seconds to perform this.\n");
  581. #endif
  582. printf ("\n");
  583. #if win
  584. printf (" sendpraat praat \"execute C:\\MyDocuments\\MyScript.praat\"\n");
  585. #else
  586. printf (" sendpraat praat \"execute ~/MyResearch/MyProject/MyScript.praat\"\n");
  587. #endif
  588. printf (" Causes the program \"praat\" to execute a script.\n");
  589. #if ! win
  590. printf (" Sendpraat will allow \"praat\" at most 10 seconds (the default time out).\n");
  591. #endif
  592. printf ("\n");
  593. printf (" sendpraat als \"for i from 1 to 5\" \"Draw circle... 0.5 0.5 0.1*i\" \"endfor\"\n");
  594. printf (" Causes the program \"als\" to draw five concentric circles\n");
  595. printf (" into its Picture window.\n");
  596. exit (0);
  597. }
  598. iarg = 1;
  599. #if ! win
  600. /*
  601. * Get time-out.
  602. */
  603. if (isdigit (argv [iarg] [0])) timeOut = atol (argv [iarg ++]);
  604. #endif
  605. /*
  606. * Get program name.
  607. */
  608. if (iarg == argc) {
  609. fprintf (stderr, "sendpraat: missing program name. Type \"sendpraat\" to get help.\n");
  610. return 1;
  611. }
  612. strcpy (programName, argv [iarg ++]);
  613. /*
  614. * Create the message string.
  615. */
  616. for (line = iarg; line < argc; line ++) length += strlen (argv [line]) + 1;
  617. length --;
  618. message = malloc (length + 1);
  619. message [0] = '\0';
  620. for (line = iarg; line < argc; line ++) {
  621. strcat (message, argv [line]);
  622. if (line < argc - 1) strcat (message, "\n");
  623. }
  624. /*
  625. * Send message.
  626. */
  627. result = sendpraat (NULL, programName, timeOut, message);
  628. if (result != NULL)
  629. { fprintf (stderr, "sendpraat: %s\n", result); exit (1); }
  630. exit (0);
  631. return 0;
  632. }
  633. #endif
  634. /* End of file sendpraat.c */