1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Naba Kumar <naba@gnome.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * SECTION:anjuta-utils
24 * @short_description: Utility functions
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-utils.h
40 #include <sys/types.h>
41 #include <sys/fcntl.h>
42 #include <sys/termios.h>
48 #include <glib/gi18n.h>
51 #include <libgnome/gnome-util.h>
53 #include <libanjuta/anjuta-utils.h>
54 #include <libanjuta/anjuta-debug.h>
56 #include <libgnomevfs/gnome-vfs.h>
58 #define FILE_BUFFER_SIZE 1024
61 anjuta_util_copy_file (gchar
* src
, gchar
* dest
, gboolean show_error
)
63 FILE *input_fp
, *output_fp
;
64 gchar buffer
[FILE_BUFFER_SIZE
];
65 gint bytes_read
, bytes_written
;
70 input_fp
= fopen (src
, "rb");
74 anjuta_util_dialog_error_system (NULL
, errno
,
75 _("Unable to read file: %s."),
80 output_fp
= fopen (dest
, "wb");
81 if (output_fp
== NULL
)
84 anjuta_util_dialog_error_system (NULL
, errno
,
85 _("Unable to create file: %s."),
93 bytes_read
= fread (buffer
, 1, FILE_BUFFER_SIZE
, input_fp
);
94 if (bytes_read
!= FILE_BUFFER_SIZE
&& ferror (input_fp
))
102 bytes_written
= fwrite (buffer
, 1, bytes_read
, output_fp
);
103 if (bytes_read
!= bytes_written
)
110 if (bytes_read
!= FILE_BUFFER_SIZE
&& feof (input_fp
))
119 if( show_error
&& (error
== FALSE
))
120 anjuta_util_dialog_error_system (NULL
, errno
,
121 _("Unable to complete file copy"));
126 anjuta_util_color_from_string (const gchar
* val
, guint16
* r
, guint16
* g
, guint16
* b
)
129 if (gdk_color_parse(val
, &color
))
138 anjuta_util_string_from_color (guint16 r
, guint16 g
, guint16 b
)
140 return g_strdup_printf("#%02x%02x%02x", r
>> 8, g
>> 8, b
>> 8);
143 /* Get a GdkColor from preferences. Free the color with gdk_color_free() */
145 anjuta_util_convert_color(AnjutaPreferences
* prefs
, const gchar
* pref_name
)
147 GdkColor
* color
= g_new0(GdkColor
, 1);
148 gchar
* color_string
= anjuta_preferences_get(prefs
, pref_name
);
149 gdk_color_parse(color_string
, color
);
154 anjuta_util_button_new_with_stock_image (const gchar
* text
,
155 const gchar
* stock_id
)
164 button
= gtk_button_new ();
166 if (GTK_BIN (button
)->child
)
167 gtk_container_remove (GTK_CONTAINER (button
),
168 GTK_BIN (button
)->child
);
170 if (gtk_stock_lookup (stock_id
, &item
))
172 label
= gtk_label_new_with_mnemonic (text
);
174 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), GTK_WIDGET (button
));
176 image
= gtk_image_new_from_stock (stock_id
, GTK_ICON_SIZE_BUTTON
);
177 hbox
= gtk_hbox_new (FALSE
, 2);
179 align
= gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
181 gtk_box_pack_start (GTK_BOX (hbox
), image
, FALSE
, FALSE
, 0);
182 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
184 gtk_container_add (GTK_CONTAINER (button
), align
);
185 gtk_container_add (GTK_CONTAINER (align
), hbox
);
186 gtk_widget_show_all (align
);
191 label
= gtk_label_new_with_mnemonic (text
);
192 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), GTK_WIDGET (button
));
194 gtk_misc_set_alignment (GTK_MISC (label
), 0.5, 0.5);
196 gtk_widget_show (label
);
197 gtk_container_add (GTK_CONTAINER (button
), label
);
203 anjuta_util_dialog_add_button (GtkDialog
*dialog
, const gchar
* text
,
204 const gchar
* stock_id
, gint response_id
)
208 g_return_val_if_fail (GTK_IS_DIALOG (dialog
), NULL
);
209 g_return_val_if_fail (text
!= NULL
, NULL
);
210 g_return_val_if_fail (stock_id
!= NULL
, NULL
);
212 button
= anjuta_util_button_new_with_stock_image (text
, stock_id
);
213 g_return_val_if_fail (button
!= NULL
, NULL
);
215 GTK_WIDGET_SET_FLAGS (button
, GTK_CAN_DEFAULT
);
217 gtk_widget_show (button
);
219 gtk_dialog_add_action_widget (dialog
, button
, response_id
);
225 anjuta_util_dialog_error (GtkWindow
*parent
, const gchar
*mesg
, ...)
230 GtkWindow
*real_parent
;
232 va_start (args
, mesg
);
233 message
= g_strdup_vprintf (mesg
, args
);
236 if (parent
&& GTK_IS_WINDOW (parent
))
238 real_parent
= parent
;
245 // Dialog to be HIG compliant
246 dialog
= gtk_message_dialog_new (real_parent
,
247 GTK_DIALOG_DESTROY_WITH_PARENT
,
249 GTK_BUTTONS_CLOSE
, message
);
250 g_signal_connect (G_OBJECT (dialog
), "response",
251 G_CALLBACK (gtk_widget_destroy
), NULL
);
252 gtk_widget_show (dialog
);
257 anjuta_util_dialog_warning (GtkWindow
*parent
, const gchar
* mesg
, ...)
262 GtkWindow
*real_parent
;
264 va_start (args
, mesg
);
265 message
= g_strdup_vprintf (mesg
, args
);
268 if (parent
&& GTK_IS_WINDOW (parent
))
270 real_parent
= parent
;
277 // Dialog to be HIG compliant
278 dialog
= gtk_message_dialog_new (real_parent
,
279 GTK_DIALOG_DESTROY_WITH_PARENT
,
281 GTK_BUTTONS_CLOSE
, message
);
282 g_signal_connect (G_OBJECT (dialog
), "response",
283 G_CALLBACK (gtk_widget_destroy
), NULL
);
284 gtk_widget_show (dialog
);
289 anjuta_util_dialog_info (GtkWindow
*parent
, const gchar
* mesg
, ...)
294 GtkWindow
*real_parent
;
296 va_start (args
, mesg
);
297 message
= g_strdup_vprintf (mesg
, args
);
300 if (parent
&& GTK_IS_WINDOW (parent
))
302 real_parent
= parent
;
308 // Dialog to be HIG compliant
309 dialog
= gtk_message_dialog_new (real_parent
,
310 GTK_DIALOG_DESTROY_WITH_PARENT
,
312 GTK_BUTTONS_CLOSE
, message
);
313 g_signal_connect (G_OBJECT (dialog
), "response",
314 G_CALLBACK (gtk_widget_destroy
), NULL
);
315 gtk_widget_show (dialog
);
320 anjuta_util_dialog_error_system (GtkWindow
* parent
, gint errnum
,
321 const gchar
* mesg
, ... )
327 GtkWindow
*real_parent
;
329 va_start (args
, mesg
);
330 message
= g_strdup_vprintf (mesg
, args
);
334 tot_mesg
= g_strconcat (message
, _("\nSystem: "),
335 g_strerror(errnum
), NULL
);
340 if (parent
&& GTK_IS_WINDOW (parent
))
342 real_parent
= parent
;
348 // Dialog to be HIG compliant
349 dialog
= gtk_message_dialog_new (real_parent
,
350 GTK_DIALOG_DESTROY_WITH_PARENT
,
352 GTK_BUTTONS_CLOSE
, tot_mesg
);
353 g_signal_connect (G_OBJECT (dialog
), "response",
354 G_CALLBACK (gtk_widget_destroy
), NULL
);
355 gtk_widget_show (dialog
);
360 anjuta_util_dialog_boolean_question (GtkWindow
*parent
, const gchar
*mesg
, ...)
366 GtkWindow
*real_parent
;
368 va_start (args
, mesg
);
369 message
= g_strdup_vprintf (mesg
, args
);
372 if (parent
&& GTK_IS_WINDOW (parent
))
374 real_parent
= parent
;
381 dialog
= gtk_message_dialog_new (real_parent
,
382 GTK_DIALOG_DESTROY_WITH_PARENT
,
383 GTK_MESSAGE_QUESTION
,
384 GTK_BUTTONS_YES_NO
, message
);
386 ret
= gtk_dialog_run (GTK_DIALOG (dialog
));
387 gtk_widget_destroy (dialog
);
390 return (ret
== GTK_RESPONSE_YES
);
394 anjuta_util_dialog_input (GtkWindow
*parent
, const gchar
*prompt
,
395 const gchar
*default_value
, gchar
**return_value
)
397 GtkWidget
*dialog
, *label
, *frame
, *entry
, *dialog_vbox
, *vbox
;
400 GtkWindow
*real_parent
;
402 if (parent
&& GTK_IS_WINDOW (parent
))
404 real_parent
= parent
;
411 dialog
= gtk_dialog_new_with_buttons (prompt
, real_parent
,
412 GTK_DIALOG_DESTROY_WITH_PARENT
,
413 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
414 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
416 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
417 dialog_vbox
= GTK_DIALOG (dialog
)->vbox
;
418 gtk_window_set_default_size (GTK_WINDOW (dialog
), 400, -1);
419 gtk_widget_show (dialog_vbox
);
421 markup
= g_strconcat ("<b>", prompt
, "</b>", NULL
);
422 label
= gtk_label_new (NULL
);
423 gtk_label_set_markup (GTK_LABEL (label
), markup
);
424 gtk_widget_show (label
);
427 frame
= gtk_frame_new (NULL
);
428 gtk_frame_set_label_widget (GTK_FRAME (frame
), label
);
429 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_NONE
);
430 gtk_container_set_border_width (GTK_CONTAINER (frame
), 10);
431 gtk_widget_show (frame
);
432 gtk_box_pack_start (GTK_BOX (dialog_vbox
), frame
, FALSE
, FALSE
, 0);
434 vbox
= gtk_vbox_new (FALSE
, 0);
435 gtk_widget_show (vbox
);
436 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 10);
437 gtk_container_add (GTK_CONTAINER (frame
), vbox
);
439 entry
= gtk_entry_new ();
440 gtk_widget_show (entry
);
441 gtk_entry_set_activates_default (GTK_ENTRY (entry
), TRUE
);
442 gtk_box_pack_start (GTK_BOX (vbox
), entry
, FALSE
, FALSE
, 0);
444 gtk_entry_set_text (GTK_ENTRY (entry
), default_value
);
446 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
448 if (gtk_entry_get_text (GTK_ENTRY (entry
)) &&
449 strlen (gtk_entry_get_text (GTK_ENTRY (entry
))) > 0)
451 *return_value
= g_strdup (gtk_entry_get_text (GTK_ENTRY (entry
)));
455 *return_value
= NULL
;
457 gtk_widget_destroy (dialog
);
458 return (res
== GTK_RESPONSE_OK
);
462 anjuta_util_prog_is_installed (gchar
* prog
, gboolean show
)
464 gchar
* prog_path
= g_find_program_in_path (prog
);
472 anjuta_util_dialog_error (NULL
, _("The \"%s\" utility is not installed.\n"
473 "Please install it."), prog
);
479 anjuta_util_get_a_tmp_file (void)
481 static gint count
= 0;
485 tmpdir
= g_get_tmp_dir ();
487 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir
, count
++, getpid ());
491 /* GList of strings operations */
493 anjuta_util_glist_from_string (const gchar
*string
)
495 gchar
*str
, *temp
, buff
[256];
497 gchar
*word_start
, *word_end
;
502 temp
= g_strdup (string
);
512 /* Remove leading spaces */
513 while (isspace (*str
) && *str
!= '\0')
518 /* Find start and end of word */
520 while (!isspace (*str
) && *str
!= '\0')
524 /* Copy the word into the buffer */
525 for (ptr
= word_start
, i
= 0; ptr
< word_end
; ptr
++, i
++)
529 list
= g_list_append (list
, g_strdup (buff
));
538 /* Prefix the strings */
540 anjuta_util_glist_strings_prefix (GList
* list
, const gchar
*prefix
)
545 g_return_if_fail (prefix
!= NULL
);
550 node
->data
= g_strconcat (prefix
, tmp
, NULL
);
551 if (tmp
) g_free (tmp
);
552 node
= g_list_next (node
);
556 /* Suffix the strings */
558 anjuta_util_glist_strings_sufix (GList
* list
, const gchar
*sufix
)
563 g_return_if_fail (sufix
!= NULL
);
568 node
->data
= g_strconcat (tmp
, sufix
, NULL
);
569 if (tmp
) g_free (tmp
);
570 node
= g_list_next (node
);
574 /* Duplicate list of strings */
576 anjuta_util_glist_strings_dup (GList
* list
)
586 new_list
= g_list_append (new_list
, g_strdup(node
->data
));
588 new_list
= g_list_append (new_list
, NULL
);
589 node
= g_list_next (node
);
595 get_real_path(const gchar
*file_name
)
599 gchar path
[PATH_MAX
+1];
600 memset(path
, '\0', PATH_MAX
+1);
601 realpath(file_name
, path
);
602 return g_strdup(path
);
608 /* Dedup a list of paths - duplicates are removed from the tail.
609 ** Useful for deduping Recent Files and Recent Projects */
611 anjuta_util_glist_path_dedup(GList
*list
)
613 GList
*nlist
= NULL
, *tmp
, *tmp1
;
616 for (tmp
= list
; tmp
; tmp
= g_list_next(tmp
))
618 path
= get_real_path((const gchar
*) tmp
->data
);
619 if (0 != stat(path
, &s
))
625 for (tmp1
= nlist
; tmp1
; tmp1
= g_list_next(tmp1
))
627 if (0 == strcmp((const char *) tmp1
->data
, path
))
635 nlist
= g_list_prepend(nlist
, path
);
638 anjuta_util_glist_strings_free(list
);
639 nlist
= g_list_reverse(nlist
);
644 sort_node (gchar
* a
, gchar
*b
)
646 if ( !a
&& !b
) return 0;
647 else if (!a
) return -1;
648 else if (!b
) return 1;
649 return strcmp (a
, b
);
652 /* Sort the list alphabatically */
654 anjuta_util_glist_strings_sort (GList
* list
)
656 return g_list_sort(list
, (GCompareFunc
)sort_node
);
659 /* Free the strings and GList */
661 anjuta_util_glist_strings_free (GList
* list
)
669 node
= g_list_next (node
);
675 anjuta_util_type_from_string (AnjutaUtilStringMap
*map
, const char *str
)
679 while (-1 != map
[i
].type
)
681 if (0 == strcmp(map
[i
].name
, str
))
689 anjuta_util_string_from_type (AnjutaUtilStringMap
*map
, int type
)
692 while (-1 != map
[i
].type
)
694 if (map
[i
].type
== type
)
702 anjuta_util_glist_from_map (AnjutaUtilStringMap
*map
)
704 GList
*out_list
= NULL
;
706 while (-1 != map
[i
].type
)
708 out_list
= g_list_append(out_list
, map
[i
].name
);
716 anjuta_util_update_string_list (GList
*p_list
, const gchar
*p_str
, gint length
)
722 for (i
= 0; i
< g_list_length (p_list
); i
++)
724 str
= (gchar
*) g_list_nth_data (p_list
, i
);
727 if (strcmp (p_str
, str
) == 0)
729 p_list
= g_list_remove (p_list
, str
);
730 p_list
= g_list_prepend (p_list
, str
);
734 p_list
= g_list_prepend (p_list
, g_strdup (p_str
));
735 while (g_list_length (p_list
) > length
)
737 str
= g_list_nth_data (p_list
, g_list_length (p_list
) - 1);
738 p_list
= g_list_remove (p_list
, str
);
745 anjuta_util_create_dir (const gchar
* d
)
747 if (g_file_test (d
, G_FILE_TEST_IS_DIR
))
755 anjuta_util_execute_shell (const gchar
*dir
, const gchar
*command
)
760 g_return_val_if_fail (command
!= NULL
, -1);
762 shell
= gnome_util_user_shell ();
768 anjuta_util_create_dir (dir
);
771 execlp (shell
, shell
, "-c", command
, NULL
);
772 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command
, shell
);
776 g_warning (_("Cannot execute command %s (using shell %s)\n"), command
, shell
);
778 // Anjuta will take care of child exit automatically.
783 anjuta_util_convert_to_utf8 (const gchar
*str
)
785 GError
*error
= NULL
;
786 gchar
*utf8_msg_string
= NULL
;
788 g_return_val_if_fail (str
!= NULL
, NULL
);
789 g_return_val_if_fail (strlen (str
) > 0, NULL
);
791 if (g_utf8_validate(str
, -1, NULL
))
793 utf8_msg_string
= g_strdup (str
);
797 gsize rbytes
, wbytes
;
798 utf8_msg_string
= g_locale_to_utf8 (str
, -1, &rbytes
, &wbytes
, &error
);
800 g_warning ("g_locale_to_utf8 failed: %s\n", error
->message
);
801 g_error_free (error
);
802 /* g_free (utf8_msg_string);
806 return utf8_msg_string
;
810 anjuta_util_parse_args_from_string (const gchar
* string
)
814 gboolean is_quote
= FALSE
;
815 gchar
* buffer
= g_new0(gchar
, strlen(string
) + 1);
832 /* The current char was escaped */
835 } else if (*s
== '\\') {
836 /* Current char is an escape */
838 } else if (*s
== quote
) {
839 /* Current char ends a quotation */
841 if (!isspace(*(s
+1)) && (*(s
+1) != '\0')) {
842 /* If there is no space after the quotation or it is not
843 the end of the string */
844 g_warning ("Parse error while parsing program arguments");
846 } else if ((*s
== '\"' || *s
== '\'')) {
848 /* Current char starts a quotation */
852 /* Just a quote char inside quote */
855 } else if (is_quote
){
856 /* Any other char inside quote */
858 } else if (isspace(*s
)) {
859 /* Any white space outside quote */
861 buffer
[idx
++] = '\0';
862 args
= g_list_append (args
, g_strdup (buffer
));
871 /* There are chars in the buffer. Flush as the last arg */
872 buffer
[idx
++] = '\0';
873 args
= g_list_append (args
, g_strdup (buffer
));
877 g_warning ("Unclosed quotation encountered at the end of parsing");
883 anjuta_util_escape_quotes(const gchar
* str
)
887 const gchar
*s
= str
;
889 g_return_val_if_fail(str
, NULL
);
892 /* We are assuming there will be less than 2048 chars to escape */
893 max_size
= strlen(str
) + 2048;
894 buffer
= g_new (gchar
, max_size
);
900 if (*s
== '\"' || *s
== '\'' || *s
== '\\')
901 buffer
[idx
++] = '\\';
909 /* Diff the text contained in uri with text. Return true if files
910 differ, FALSE if they are identical.
911 FIXME: Find a better algorithm, this seems ineffective */
913 gboolean
anjuta_util_diff(const gchar
* uri
, const gchar
* text
)
915 GnomeVFSFileSize bytes_read
;
917 GnomeVFSFileInfo info
;
918 GnomeVFSHandle
* handle
= NULL
;
920 gnome_vfs_get_file_info(uri
, &info
, GNOME_VFS_FILE_INFO_DEFAULT
);
922 if (info
.size
== 0 && text
== NULL
)
924 else if (info
.size
== 0 || text
== NULL
)
927 file_text
= g_new0(gchar
, info
.size
+ 1);
929 if (gnome_vfs_open(&handle
, uri
, GNOME_VFS_OPEN_READ
!= GNOME_VFS_OK
))
932 if ((gnome_vfs_read(handle
, file_text
, info
.size
, &bytes_read
) == GNOME_VFS_OK
)
933 && (bytes_read
== info
.size
))
935 gnome_vfs_close(handle
);
937 if ((g_utf8_strlen(file_text
, -1) == g_utf8_strlen(text
, -1))
938 && strcmp(file_text
, text
) == 0)
944 gnome_vfs_close(handle
);
950 anjuta_util_path_has_extension (const gchar
*path
, const gchar
*ext
)
952 if (strlen (path
) <= strlen (ext
))
954 if ((path
[strlen (path
) - strlen (ext
) - 1] == '.') &&
955 (strcmp (&path
[strlen (path
) - strlen (ext
)], ext
) == 0))
961 anjuta_util_get_uri_mime_type (const gchar
*uri
)
963 GnomeVFSURI
*vfs_uri
;
967 g_return_val_if_fail (uri
!= NULL
, NULL
);
969 vfs_uri
= gnome_vfs_uri_new (uri
);
971 path
= gnome_vfs_uri_get_path (vfs_uri
);
975 /* If Anjuta is not installed in system gnome prefix, the mime types
976 * may not have been correctly registed. In that case, we use the
977 * following mime detection
981 mime_type
= gnome_vfs_get_mime_type (uri
);
983 else if (anjuta_util_path_has_extension (path
, "anjuta"))
985 mime_type
= g_strdup ("application/x-anjuta");
987 else if (anjuta_util_path_has_extension (path
, "prj"))
989 mime_type
= g_strdup ("application/x-anjuta-old");
991 else if (anjuta_util_path_has_extension (path
, "ui"))
993 mime_type
= g_strdup ("text/xml");
995 else if (anjuta_util_path_has_extension (path
, "glade"))
997 mime_type
= g_strdup ("application/x-glade");
1001 mime_type
= gnome_vfs_get_mime_type (uri
);
1005 gnome_vfs_uri_unref (vfs_uri
);
1009 #ifndef HAVE_LIBUTIL
1012 static int ptym_open (char *pts_name
);
1013 static int ptys_open (int fdm
, char * pts_name
);
1016 login_tty(int ttyfd
)
1028 /* First disconnect from the old controlling tty. */
1030 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1033 ioctl(fd
, TIOCNOTTY
, NULL
);
1037 //syslog(LOG_WARNING, "NO CTTY");
1038 #endif /* TIOCNOTTY */
1040 /* Verify that we are successfully disconnected from the controlling tty. */
1041 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
);
1044 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1048 /* Make it our controlling tty. */
1050 ioctl(ttyfd
, TIOCSCTTY
, NULL
);
1051 #endif /* TIOCSCTTY */
1053 fdname
= ttyname (ttyfd
);
1054 fd
= open(fdname
, O_RDWR
);
1056 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1060 /* Verify that we now have a controlling tty. */
1061 fd
= open("/dev/tty", O_WRONLY
);
1064 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1069 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1071 RETSIGTYPE (*sig
)();
1072 sig
= signal(SIGHUP
, SIG_IGN
);
1074 signal(SIGHUP
, sig
);
1077 fd
= open(fdname
, O_RDWR
);
1080 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1102 openpty(int *amaster
, int *aslave
, char *name
, struct termios
*termp
,
1103 struct winsize
*winp
)
1106 *amaster
= ptym_open(line
);
1109 *aslave
= ptys_open(*amaster
, line
);
1117 #define TCSAFLUSH TCSETAF
1120 (void) tcsetattr(*aslave
, TCSAFLUSH
, termp
);
1123 (void) ioctl(*aslave
, TIOCSWINSZ
, (char *)winp
);
1129 ptym_open(char * pts_name
)
1135 strcpy(pts_name
, "/dev/ptmx");
1136 fdm
= open(pts_name
, O_RDWR
);
1139 if (grantpt(fdm
) < 0) { /* grant access to slave */
1143 if (unlockpt(fdm
) < 0) { /* clear slave's lock flag */
1148 if (ptr
== NULL
) { /* get slave's name */
1152 strcpy(pts_name
, ptr
); /* return name of slave */
1153 return fdm
; /* return fd of master */
1157 strcpy(pts_name
, "/dev/ptyXY");
1158 /* array index: 012345689 (for references in following code) */
1159 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
!= 0; ptr1
++) {
1160 pts_name
[8] = *ptr1
;
1161 for (ptr2
= "0123456789abcdef"; *ptr2
!= 0; ptr2
++) {
1162 pts_name
[9] = *ptr2
;
1163 /* try to open master */
1164 fdm
= open(pts_name
, O_RDWR
);
1166 if (errno
== ENOENT
) /* different from EIO */
1167 return -1; /* out of pty devices */
1169 continue; /* try next pty device */
1171 pts_name
[5] = 't'; /* chage "pty" to "tty" */
1172 return fdm
; /* got it, return fd of master */
1175 return -1; /* out of pty devices */
1180 ptys_open(int fdm
, char * pts_name
)
1184 /* following should allocate controlling terminal */
1185 fds
= open(pts_name
, O_RDWR
);
1190 if (ioctl(fds
, I_PUSH
, "ptem") < 0) {
1195 if (ioctl(fds
, I_PUSH
, "ldterm") < 0) {
1200 if (ioctl(fds
, I_PUSH
, "ttcompat") < 0) {
1206 if (ioctl(fdm
, I_PUSH
, "pckt") < 0) {
1212 if (ioctl(fdm
, I_SRDOPT
, RMSGN
|RPROTDAT
) < 0) {
1221 struct group
*grptr
;
1223 grptr
= getgrnam("tty");
1225 gid
= grptr
->gr_gid
;
1227 gid
= -1; /* group tty is not in the group file */
1228 /* following two functions don't work unless we're root */
1229 chown(pts_name
, getuid(), gid
);
1230 chmod(pts_name
, S_IRUSR
| S_IWUSR
| S_IWGRP
);
1231 fds
= open(pts_name
, O_RDWR
);
1241 forkpty(int *amaster
, char *name
, struct termios
*termp
, struct winsize
*winp
)
1243 int master
, slave
, pid
;
1245 if (openpty(&master
, &slave
, name
, termp
, winp
) == -1)
1247 switch (pid
= fork()) {
1266 int scandir(const char *dir
, struct dirent
***namelist
,
1267 int (*select
)(const struct dirent
*),
1268 int (*compar
)(const struct dirent
**, const struct dirent
**))
1271 struct dirent
*entry
;
1275 if ((d
=opendir(dir
)) == NULL
)
1279 while ((entry
=readdir(d
)) != NULL
)
1281 if (select
== NULL
|| (select
!= NULL
&& (*select
)(entry
)))
1283 *namelist
=(struct dirent
**)realloc((void *)(*namelist
),
1284 (size_t)((i
+1)*sizeof(struct dirent
*)));
1285 if (*namelist
== NULL
) return(-1);
1286 entrysize
=sizeof(struct dirent
)-sizeof(entry
->d_name
)+strlen(entry
->d_name
)+1;
1287 (*namelist
)[i
]=(struct dirent
*)malloc(entrysize
);
1288 if ((*namelist
)[i
] == NULL
) return(-1);
1289 memcpy((*namelist
)[i
], entry
, entrysize
);
1293 if (closedir(d
)) return(-1);
1294 if (i
== 0) return(-1);
1296 qsort((void *)(*namelist
), (size_t)i
, sizeof(struct dirent
*), compar
);
1301 #endif /* HAVE_LIBUTIL */