OSDev.org

The Place to Start for Operating System Developers
It is currently Sun May 05, 2024 9:20 am

All times are UTC - 6 hours




Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 
Author Message
 Post subject: Interrupts
PostPosted: Wed Aug 14, 2013 7:56 pm 
Offline

Joined: Tue Jul 30, 2013 5:23 pm
Posts: 11
So far I haven't had much luck with this at all. I don't know if any of what I have is working because none of it works until it all works, so I don't know where the problem is. Here is the various relavant pieces of code.
idt.h
Code:
#ifndef __IDT_H
#define __IDT_H

#define IDT_TASK_32 0x5
#define IDT_INT_16 0x6
#define IDT_TRAP_16 0x7
#define IDT_INT_32 0xE
#define IDT_TRAP_32 0xF
#define IDT_SEG_STORAGE 0x10
#define IDT_DPL0 0x0
#define IDT_DPL1 0x20
#define IDT_DPL2 0x40
#define IDT_DPL3 0x60
#define IDT_PRESENT 0x80

struct IDTDescr{
    uint16_t offset_1; // offset bits 0..15
    uint16_t selector; // a code segment selector in GDT or LDT
    uint8_t zero;      // unused, set to 0
    uint8_t type_attr; // type and attributes, see below
    uint16_t offset_2; // offset bits 16..31
};

struct IDTDescr IDT[48];
void setIdt(void *ptr, uint16_t size);
#endif

Code:
#include "gdt.h"
gdt_descriptor create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
{
    gdt_descriptor descriptor;

    // Create the high 32 bit segment
    descriptor  =  limit       & 0x000F0000;         // set limit bits 19:16
    descriptor |= (flag <<  8) & 0x00F0FF00;         // set type, p, dpl, s, g, d/b, l and avl fields
    descriptor |= (base >> 16) & 0x000000FF;         // set base bits 23:16
    descriptor |=  base        & 0xFF000000;         // set base bits 31:24

    // Shift by 32 to allow for low part of segment
    descriptor <<= 32;

    // Create the low 32 bit segment
    descriptor |= base  << 16;                       // set base bits 15:0
    descriptor |= limit  & 0x0000FFFF;               // set limit bits 15:0

    return descriptor;
}

now I have two keyboard codes (i've tried both). one uses else if statements and the other doesn't have the right scan codes for my computer. I think the problem might be here, becauese I don't know how the keyboard sends an interrupt. anyway, here's one
Code:
#include "io.h"
#include "string.h"
int ccol;
int led_stat=0;
int crow;
char keysq[100];
int scan(){
   char oldkey;
   char key;
   for (;;){
      oldkey=key;
      key=inportb(0x60);
      if(!(oldkey==key)){
         return key;
      }
   }
}


void klights(){
   if (led_stat == 0){
      outportb(0x60, 0xED);
      while(inportb(0x64) & 2);
      outportb(0x60, 4);
      while(inportb(0x64) & 2);
      led_stat++;
   }
   else if (led_stat == 1){
      outportb(0x60, 0xED);
      while(inportb(0x64) & 2);
      outportb(0x60, 0);
      while(inportb(0x64) & 2);
      led_stat=0;
   }
}
char * keyboard(){
   for(int i=0;i<100;i++)
      keysq[i] = 0;
   int kcount = 0;
   int code = 0;
   scan(); //so it doesn't think its enter
   outportb(0x60, 0xF4);
   while (1){
      code = scan();
      if (code == 0x01){
         print("esc");
         kcount+=3;
      }
      else if (code == 0x02){
         print("1");
         keysq[kcount]='1';
         kcount++;
      
      }
      else if (code == 0x03){
         print("2");
         keysq[kcount]='2';
         kcount++;
      }
      else if (code == 0x04){
         print("3");
         keysq[kcount]='3';
         kcount++;
      }
      else if (code == 0x05){
         print("4");
         keysq[kcount]='4';
         kcount++;
      }
      else if (code == 0x06){
         print("5");
         keysq[kcount]='5';
         kcount++;
      }
      else if (code == 0x07){
         print("6");
         keysq[kcount]='6';
         kcount++;
      }
      else if (code == 0x08){
         print("7");
         keysq[kcount]='7';
         kcount++;
      }
      else if (code == 0x09){
         print("8");
         keysq[kcount]='8';
         kcount++;
      }
      else if (code == 0x0A){
         print("9");
         keysq[kcount]='9';
         kcount++;
      }
      else if (code == 0x0B){
         print("0");
         keysq[kcount]='0';
         kcount++;
      }
      else if (code == 0x0C){
         print("-");
         keysq[kcount]='-';
         kcount++;
      }
      else if (code == 0x0D){
         print("=");
         keysq[kcount]='=';
         kcount++;
      }
      else if (code == 0x0E){
         if (kcount > 0){
            ccol-=2;
            cursor-=2;
            print(" ");
            cursor-=2;//                    BKSP
            kcount--;
            keysq[kcount]=0;
         }
      }
      else if (code == 0x0F){
         print("    ");
      }
      else if (code == 0x10){
         print("q");
         keysq[kcount]='q';
         kcount++;
      }
      else if (code == 0x11){
         print("w");
         keysq[kcount]='w';
         kcount++;
   
      }
      else if (code == 0x12){
         print("e");
         keysq[kcount]='e';
         kcount++;
      }
      else if (code == 0x13){
         print("r");
         keysq[kcount]='r';
         kcount++;
      }
      else if (code == 0x14){
         print("t");
         keysq[kcount]='t';
         kcount++;
      }
      else if (code == 0x15){
         print("y");
         keysq[kcount]='y';
         kcount++;
      }
      else if (code == 0x16){
         print("u");
         keysq[kcount]='u';
         kcount++;
      }
      else if (code == 0x17){
         print("i");
         keysq[kcount]='i';
         kcount++;
      }
      else if (code == 0x18){
         print("o");
         keysq[kcount]='o';
         kcount++;
      }
      else if (code == 0x19){
         print("p");
         keysq[kcount]='p';
         kcount++;
      }
      else if (code == 0x1A){
         print("[");
         keysq[kcount]='[';
         kcount++;
      }
      else if (code == 0x1B){
         print("]");
         keysq[kcount]=']';
         kcount++;
      }
      else if (code == 0x1C){
                     //            ENTER
         code = 0;
         print("\n");
         break;
      }
      else if (code == 0x1D){
         print("lctrl");
         kcount+=5;
      }
      else if (code == 0x1E){
         print("a");
         keysq[kcount]='a';
         kcount++;
      }
      else if (code == 0x1F){
         print("s");
         keysq[kcount]='s';
         kcount++;
      }
      else if (code == 0x20){
         print("d");
         keysq[kcount]='d';
         kcount++;
      }
      else if (code == 0x21){
         print("f");
         keysq[kcount]='f';
         kcount++;
      }
      else if (code == 0x22){
         print("g");
         keysq[kcount]='g';
         kcount++;
      }
      else if (code == 0x23){
         print("h");
         keysq[kcount]='h';
         kcount++;
      }
      else if (code == 0x24){
         print("j");
         keysq[kcount]='j';
         kcount++;
      }
      else if (code == 0x25){
         print("k");
         keysq[kcount]='[';
         kcount++;
      }
      else if (code == 0x26){
         print("l");
         keysq[kcount]='l';
         kcount++;
      }
      else if (code == 0x27){
         print(";");
         keysq[kcount]=';';
         kcount++;
      }
      else if (code == 0x28){
         print("'");
         keysq[kcount]='\'';
         kcount++;
      }
      else if (code == 0x29){
         print("`");
         keysq[kcount]='`';
         kcount++;
      }
      else if (code == 0x2A){
         print("lshift");
         kcount+=6;
      }
      else if (code == 0x2B){
         print("\\");
         kcount++;
      }
      else if (code == 0x2C){
         print("z");
         keysq[kcount]='z';
         kcount++;
      }
      else if (code == 0x2D){
         print("x");
         keysq[kcount]='x';
         kcount++;
      }
      else if (code == 0x2E){
         print("c");
         keysq[kcount]='c';
         kcount++;
      }
      else if (code == 0x2F){
         print("v");
         keysq[kcount]='v';
         kcount++;
      }
      else if (code == 0x30){
         print("b");
         keysq[kcount]='b';
         kcount++;
      }
      else if (code == 0x31){
         print("n");
         keysq[kcount]='n';
         kcount++;
      }
      else if (code == 0x32){
         print("m");
         keysq[kcount]='m';
         kcount++;
      }
      else if (code == 0x33){
         print(",");
         keysq[kcount]=',';
         kcount++;
      }
      else if (code == 0x34){
         print(".");
         keysq[kcount]='.';
         kcount++;
      }
      else if (code == 0x35){
         print("/");
         keysq[kcount]='/';
         kcount++;
      }
      else if (code == 0x36){
         print("rshift");
         kcount+=6;
      }
      else if (code == 0x38){
         print("lalt");
         kcount+=4;
      }
      else if (code == 0x39){
         print(" ");
         kcount++;
      }
      else if (code == 0x3A){
         klights();
      }   
   }
   return keysq;
}

and
Code:
#include "string.h"
#include "io.h"
#include "kb.h"
/* KBDUS means US Keyboard Layout. This is a scancode table
*  used to layout a standard US keyboard. I have left some
*  comments in to give you an idea of what key is what, even
*  though I set it's array index to 0. You can change that to
*  whatever you want using a macro, if you wish! */
unsigned char kbdus[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8',   /* 9 */
  '9', '0', '-', '=', '\b',   /* Backspace */
  '\t',         /* Tab */
  'q', 'w', 'e', 'r',   /* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',   /* Enter key */
    0,         /* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',   /* 39 */
'\'', '`',   0,      /* Left shift */
'\\', 'z', 'x', 'c', 'v', 'b', 'n',         /* 49 */
  'm', ',', '.', '/',   0,            /* Right shift */
  '*',
    0,   /* Alt */
  ' ',   /* Space bar */
    0,   /* Caps lock */
    0,   /* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,   /* < ... F10 */
    0,   /* 69 - Num lock*/
    0,   /* Scroll Lock */
    0,   /* Home key */
    0,   /* Up Arrow */
    0,   /* Page Up */
  '-',
    0,   /* Left Arrow */
    0,
    0,   /* Right Arrow */
  '+',
    0,   /* 79 - End key*/
    0,   /* Down Arrow */
    0,   /* Page Down */
    0,   /* Insert Key */
    0,   /* Delete Key */
    0,   0,   0,
    0,   /* F11 Key */
    0,   /* F12 Key */
    0,   /* All other keys are undefined */
};



/* Handles the keyboard interrupt */
void keyboard_handler()
//struct regs *r
{

    unsigned char scancode;

    /* Read from the keyboard's data buffer */
    scancode = inportb(0x60);

    /* If the top bit of the byte we read from the keyboard is
    *  set, that means that a key has just been released */
    if (scancode & 0x80)
    {
        /* You can use this one to see if the user released the
        *  shift, alt, or control keys... */
    }
    else
    {
        /* Here, a key was just pressed. Please note that if you
        *  hold a key down, you will get repeated key press
        *  interrupts. */

        /* Just to show you how this works, we simply translate
        *  the keyboard scancode into an ASCII value, and then
        *  display it to the screen. You can get creative and
        *  use some flags to see if a shift is pressed and use a
        *  different layout, or you can add another 128 entries
        *  to the above layout to correspond to 'shift' being
        *  held. If shift is held using the larger lookup table,
        *  you would add 128 to the scancode when you look for it */
      char hi[2];
      char oldkey;
      char key;
      for (;;){
         oldkey=key;
         key=inportb(0x60);
         if(!(oldkey==key)){
            hi[0] = kbdus[scancode];
            print(hi);
         }
      }
    }
}

and here is the main function
Code:
#include <stdint.h>
#include <string.h>
#include "pic.h"
#include "io.h"
//#include "keyboard.h"
#include "string.h"
#include "gdt.h"
#include "idt.h"
#include "kb.h"
void init_gdt(void);
void init_idt(void);
void exit(void);
void _interrupt_handler(void);

void kmain(void)
{
    extern uint32_t magic;
    if ( magic != 0x2BADB002 )
    {
       print("Something went not according to specs.");
      exit();
    }

   kclear();
    print("initializing GDT...\n");
    init_gdt();
    print("initializing IDT...\n");
    init_idt();
   print("initializing keyboard...\n");
   outportb(0x60, 0xF4);
   //print("initializing PICs...\n");
   //init_pics(0x20, 0x28);
   cprint("Jonathan's OS\n", 2);
   update_cursor();
   while (1)
      keyboard_handler();  //this should call one of the keyboard functions
   /*while(1){
      char * input = keyboard();
      if (strcheck(input, "help") == 1){
         print("supported commands:\nhelp - displays this message.\nclear - clears the screen.\nreboot - might make it restart.\n");
      }
      else if (strcheck(input, "clear") ==1)
      {
         kclear();
      }
      else if (strcheck(input, "reboot") == 1)
      {
         exit();
         print("this needs to be fixed.  BAD.");
      }
      else{
         print("don't know that one\n");
      }
   }*/
   
}
void exit(void){
   while(inportb(0x64) & 0x02);
   outportb(0x64, 0xFE);
}
void init_gdt(void) {
    /*GDT[0] = ((sizeof(gdt_descriptor) * GDT_ENTRIES - 1) & 0xFFFF)
            | ((uint32_t)GDT) << 16;*/
    GDT[1] = create_descriptor(0, 0xFFFFF, GDT_CODE_PL0);
    GDT[2] = create_descriptor(0, 0xFFFFF, GDT_DATA_PL0);
    setGdt(GDT, sizeof(GDT));
}
void init_idt(void) {
    for (unsigned int i = 0; i < sizeof(IDT); i++) {
        *(((char *)IDT)+i) = 0;
    }
    IDT[1].offset_1 = ((uint32_t)(&_interrupt_handler)) & 0xFFFF;
    IDT[1].offset_2 = ((uint32_t)(&_interrupt_handler)) >> 16;
    IDT[1].selector = 0x08;
    IDT[1].type_attr = IDT_DPL0 | IDT_INT_32 | IDT_PRESENT;
    setIdt(IDT, sizeof(IDT));
}
void _interrupt_handler(void) {
    print("interrupt");
}

the big block that's commented out only works with one keyboard function. the pic is commented out because of a line that I think disables interrupts.
here is the pics code
Code:
#include "pic.h"
#include "io.h"




void init_pics(int pic1, int pic2)
{
   /* send ICW1 */
   outportb(PIC1, ICW1);
   outportb(PIC2, ICW1);

   /* send ICW2 */
   outportb(PIC1 + 1, pic1);   /* remap */
   outportb(PIC2 + 1, pic2);   /*  pics */

   /* send ICW3 */
   outportb(PIC1 + 1, 4);   /* IRQ2 -> connection to slave */
   outportb(PIC2 + 1, 2);

   /* send ICW4 */
   outportb(PIC1 + 1, ICW4);
   outportb(PIC2 + 1, ICW4);

   /* disable all IRQs */
   outportb(PIC1 + 1, 0xFF);
}



I hope someone can help,
thanks,
johnyburd


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Wed Aug 14, 2013 11:50 pm 
Offline
Member
Member
User avatar

Joined: Tue Dec 27, 2011 7:57 am
Posts: 368
I think everything would move along faster, if:

1. You state exactly what is the issue with the code you have.
2. You don't post a large code dump, followed by 'help me'
3. You state what you've tried to debug the issue, instead of leaving everything to strangers on the internet.


Not to mention your if-else loop is hideously ugly.



EDIT:

Johnyburd wrote:
... because of a line that I think disables interrupts...


Johnyburd wrote:
I think


Code:
   /* disable all IRQs */
   outportb(PIC1 + 1, 0xFF);


Perhaps you need to reconsider your problem.

_________________
[nx] kernel: http://github.com/zhiayang/nx


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Thu Aug 15, 2013 12:32 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4597
Location: Chichester, UK
I get the impression that you are cut and pasting code from various sources without any real understanding of how it works. That is unlikely to be successful with a complicated subject like this.

Learn how to debug - single stepping through code if necessary - and it will help you understand the code and perhaps spot your error. But I doubt that anyone here is going to do that for you.


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Thu Aug 15, 2013 4:37 am 
Offline

Joined: Tue Jul 30, 2013 5:23 pm
Posts: 11
My cousin did write some of this. I'm sorry that I wasn't clear, but I believe it should be printing interrupt, everytime a key is pressed on the keyboard. And The reason I'm asking for help is so that I can understand it.
Also, yes I'm sorry about the else if statements, I'm working on that, but the only thing I've tried is using the other keyboard driver (the one without else if) because it came from a tutoral that was supposed to work with interrupts.

So really the question is why isn't it printing "interrupt" and where is the problem.

The reason I need you guys' help is because I don't understand all of the code. I thought this would be a better place to learn it because I could talk to real people.

The only thing that I copied and pasted was the code for the PICs and that's hardly relavant since its never used.

I'm sorry for the vague question at first
Thanks,
Johnyburd


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Tue Aug 20, 2013 4:27 am 
Offline

Joined: Tue Jul 30, 2013 5:23 pm
Posts: 11
Could someone at least direct me to a good tutorial?
(besides osdev wiki)
thanks,
johnyburd


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Tue Aug 20, 2013 7:50 am 
Offline
Member
Member
User avatar

Joined: Tue Dec 27, 2011 7:57 am
Posts: 368
Johnyburd wrote:
Could someone at least direct me to a good tutorial?
(besides osdev wiki)
thanks,
johnyburd



Again, as iansjack said, if you don't solve your problem, here's what's going to happen:

1. You'll look for another tutorial (assuming you find one)
2. You'll do what you did and copy-paste the code.
3. It would likely break, so you'd either (a), ask your 'cousin' or (b), ask here.
4. We'd probably ask you to debug your problem again.
5. jmp 0x1


You've shown no evidence of actually trying to debug your problem. The most basic thing you can do is to put halts/print messages every step of the way, that way you know what code is failing and where.

Already your comment
JohnnyBurd wrote:
... because of a line that I think disables interrupts...


shows your total lack of understanding of what you're (or your code is) actually doing.
A shot in the dark here, but
JohnnyBurd wrote:
The only thing that I copied and pasted was the code for the PICs and that's hardly relavant since its never used.


might suggest you're not remapping the PICs properly. Clearly, not exactly "hardly relevant", as you say.


Again, it might seem like we're all assholes trying to shoot you down for every little mistake, but the nature of this forum is that there needs to be a certain level of understanding, both between the community here and between you and your code.

First thing's first, use something like bochs to step through your code and find out what's going on.

_________________
[nx] kernel: http://github.com/zhiayang/nx


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Tue Aug 20, 2013 6:19 pm 
Offline

Joined: Tue Jul 30, 2013 5:23 pm
Posts: 11
Well first, I just want to tell you I haven't copied and pasted any code that is being used here. Also, I realize that I'm not at that level, I just don't know how to get there. I don't understand how to debug it. I wanted you to help me. If you don't want to, then that's fine, but I want help learning how to do it. I don't want a tutorial where I can copy and paste the code. I'm trying to learn it. that's why I asked for a good tutorial.

I don't think its fair to tell me I'm a terrible coder because I said "because of a line that I think disables interrupts..." It was rather obvious there. Being able to read someone else's comments has absolutely nothing to do with my knowledge of the language.

Also, the reason I asked for a good tutorial is that the nature of every single tutorial or forum or wiki that I've come across requires "a certain level of understanding". Consequently, it is totally impossible for people like me to learn how! I hoped talking to real people would help me understand, but like I said, If you don't want to help me, that's fine. I'd just like to know where I can learn about this.

I use bochs to test the os, I'm not sure how that helps... I just want to have some code that explains how it works at every part so I can actually understand and learn.

Thanks,
Johnyburd


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Wed Aug 21, 2013 12:40 am 
Offline
Member
Member
User avatar

Joined: Thu May 12, 2011 7:24 pm
Posts: 89
You correctly identified your most important problem in your original post:
Johnyburd wrote:
I don't know if any of what I have is working because none of it works until it all works, so I don't know where the problem is.

Johnyburd wrote:
I don't understand how to debug it. I wanted you to help me. If you don't want to, then that's fine, but I want help learning how to do it.

Here's how to debug:

  1. Find what's broken.
  2. Fix it.
  3. Repeat as needed.

Step 1 is usually the hardest. Don't make it even harder on yourself by writing a bunch of code that you hope will do what you want, and then trying to figure out why it doesn't work when you're done. Instead, break whatever it is that you want to do down into pieces that you can understand on their own, and figure out which pieces depend on which others. Then work on them in order, testing as you go, so that at as you go from one piece to the next, you can be reasonably certain that you're building on a solid foundation, and that any problems you encounter are in the new code.

For example, for interrupts to work at all, you have to be able to create an IDT containing properly-formatted descriptors and tell the processor where to find it. You can test that much by writing a simple handler to print a single character to the screen, pointing a descriptor in your IDT at that handler, and then calling it as a software interrupt. If that much works, you can check your PIC mappings by setting the descriptor for IRQ0 to call that same handler, then unmasking only IRQ0 and enabling interrupts. If you get a bunch of characters printed instead of a triple fault, then your handler is getting called each time the PIT fires (18.2 times per second by default), so you've correctly mapped IRQ0 to that descriptor. Try setting your handler for IRQ1 instead, then unmasking only IRQ1, enabling interrupts, and hitting a key. If it does work, it will only work once since you're not reading the scan code from the keyboard controller, but it will prove that you can register an interrupt handler for the keyboard. Once you're that far, modify your handler to read the actual byte received from the keyboard controller and print it instead of just a single character. Then you should be able to receive and see the full sequence of bytes sent by each keypress / release. And when you can do that, you can start working on converting scan codes to ASCII or whatever representation you want to use, keeping track of alt / ctrl / shift status, etc.

If you have problems with the individual steps, read the wiki. Search the forums. Search the rest of the Web. You're not the first person to have had these problems, or these questions. So take advantage of that fact, and learn from the answers that have already been given. Part of learning is figuring out how to find information and make use of it on your own. If you've done all that and still have questions, then at least try to ask them the smart way.

Johnyburd wrote:
Also, the reason I asked for a good tutorial is that the nature of every single tutorial or forum or wiki that I've come across requires "a certain level of understanding". Consequently, it is totally impossible for people like me to learn how!

So who wrote the tutorial that brought the first tutorial writer up to that level of understanding? It's not impossible for you to learn. You just have to do it in manageable pieces.

Johnyburd wrote:
I use bochs to test the os, I'm not sure how that helps...

Have you read the part of the Bochs documentation that describes the integrated debugger that lets you step through your code one instruction at a time, check the contents of the registers and memory, and various other things that might help you understand what your code is actually doing when it's not doing what you think it should be doing?

_________________
Those who understand Unix are doomed to copy it, poorly.


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Wed Aug 21, 2013 1:49 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4597
Location: Chichester, UK
Quote:
Well first, I just want to tell you I haven't copied and pasted any code that is being used here.
...
I don't think its fair to tell me I'm a terrible coder because I said "because of a line that I think disables interrupts..." It was rather obvious there. Being able to read someone else's comments has absolutely nothing to do with my knowledge of the language.
Those two sentences don't make sense taken together. If you haven't used anyone else's code then what is there to understand in the comments?

As for debugging, I would say that you are trying to run before you can walk. Go back to writing some simple programs, both in C and assembler, and learn how to use a debugger to singl-step through them, inspect variables and registers, etc. Once you can do that with a simple program you will be in a better position to start OS coding.


Top
 Profile  
 
 Post subject: Re: Interrupts
PostPosted: Wed Aug 21, 2013 7:13 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9301
Location: On the balcony, where I can actually keep 1½m distance
Johnyburd wrote:
Well first, I just want to tell you I haven't copied and pasted any code that is being used here.
Google says you're lying. I think that only emphasizes that the first bug that needs to be fixed now is you, and not the code.

_________________
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Amazonbot [bot], Bing [Bot], SemrushBot [Bot] and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group